{% extends 'base.html' %}
{% load static %}

{% block title %}实验平台 - 机械臂实验系统{% endblock %}

{% block extra_css %}
<style>
    .platform-container {
        max-width: 1200px;
        margin: 0 auto;
    }
    
    .experiment-title {
        margin-bottom: 2rem;
        display: flex;
        justify-content: space-between;
        align-items: center;
    }
    
    .experiment-status {
        display: inline-block;
        padding: 5px 15px;
        border-radius: 20px;
        font-size: 0.9rem;
        color: white;
    }
    
    .status-pending {
        background-color: #6c757d;
    }
    
    .status-in_progress {
        background-color: #17a2b8;
    }
    
    .status-completed {
        background-color: #28a745;
    }
    
    .status-failed {
        background-color: #dc3545;
    }
    
    .steps-container {
        margin-bottom: 2rem;
    }
    
    .step-item {
        display: flex;
        margin-bottom: 5px;
    }
    
    .step-number {
        width: 30px;
        height: 30px;
        border-radius: 50%;
        background-color: #f8f9fa;
        border: 1px solid #dee2e6;
        display: flex;
        align-items: center;
        justify-content: center;
        font-weight: bold;
        margin-right: 15px;
    }
    
    .step-number.active {
        background-color: #007bff;
        color: white;
        border-color: #007bff;
    }
    
    .step-number.completed {
        background-color: #28a745;
        color: white;
        border-color: #28a745;
    }
    
    .step-content {
        flex: 1;
        padding: 5px 0;
    }
    
    .step-content.active {
        font-weight: bold;
    }
    
    .step-content.disabled {
        color: #adb5bd;
    }
    
    .experiment-area {
        border: 1px solid #dee2e6;
        border-radius: 8px;
        padding: 20px;
        background-color: #f8f9fa;
        min-height: 500px;
        margin-bottom: 2rem;
    }
    
    .robot-view {
        background-color: #222;
        height: 400px;
        border-radius: 8px;
        overflow: hidden;
        position: relative;
        margin-bottom: 1rem;
    }
    
    .robot-canvas {
        width: 100%;
        height: 100%;
        cursor: grab;
    }
    
    .robot-canvas:active {
        cursor: grabbing;
    }
    
    .control-panel {
        background-color: white;
        border-radius: 8px;
        padding: 20px;
        box-shadow: 0 2px 10px rgba(0, 0, 0, 0.05);
    }
    
    .control-title {
        font-weight: bold;
        margin-bottom: 1rem;
        padding-bottom: 0.5rem;
        border-bottom: 1px solid #eee;
    }
    
    .instruction {
        padding: 10px;
        background-color: #f0f0f0;
        border-radius: 5px;
        margin-bottom: 15px;
    }
    
    .instruction.highlight {
        background-color: #e7f5ff;
        border-left: 4px solid #007bff;
    }
    
    .btn-confirm {
        margin-top: 1rem;
        width: 100%;
    }
    
    .feedback-message {
        padding: 10px;
        border-radius: 5px;
        margin-top: 1rem;
        display: none;
    }
    
    .feedback-success {
        background-color: #d4edda;
        color: #155724;
        border: 1px solid #c3e6cb;
    }
    
    .feedback-error {
        background-color: #f8d7da;
        color: #721c24;
        border: 1px solid #f5c6cb;
    }
    
    .operation-hint {
        text-align: center;
        padding: 8px;
        background-color: rgba(0,0,0,0.5);
        color: white;
        position: absolute;
        bottom: 10px;
        left: 50%;
        transform: translateX(-50%);
        border-radius: 20px;
        font-size: 0.9rem;
        z-index: 5;
        display: none;
    }
</style>
{% endblock %}

{% block content %}
<div class="platform-container">
    <div class="experiment-title">
        <h2>实验平台</h2>
        <div>
            <span class="experiment-status status-{{ experiment.status }}">
                {{ experiment.get_status_display }}
            </span>
            <span class="ms-2">开始时间: {{ experiment.start_time|date:"Y-m-d H:i" }}</span>
        </div>
    </div>
    
    <div class="row">
        <div class="col-md-3">
            <div class="steps-container">
                <h4 class="mb-3">实验步骤</h4>
                
                <div class="step-item">
                    <div class="step-number {% if experiment.current_step == 1 %}active{% elif experiment.current_step > 1 %}completed{% endif %}">
                        {% if experiment.current_step > 1 %}<i class="bi bi-check"></i>{% else %}1{% endif %}
                    </div>
                    <div class="step-content {% if experiment.current_step == 1 %}active{% elif experiment.current_step < 1 %}disabled{% endif %}">
                        定位螺丝
                    </div>
                </div>
                
                <div class="step-item">
                    <div class="step-number {% if experiment.current_step == 2 %}active{% elif experiment.current_step > 2 %}completed{% endif %}">
                        {% if experiment.current_step > 2 %}<i class="bi bi-check"></i>{% else %}2{% endif %}
                    </div>
                    <div class="step-content {% if experiment.current_step == 2 %}active{% elif experiment.current_step < 2 %}disabled{% endif %}">
                        扣住螺丝
                    </div>
                </div>
                
                <div class="step-item">
                    <div class="step-number {% if experiment.current_step == 3 %}active{% elif experiment.current_step > 3 %}completed{% endif %}">
                        {% if experiment.current_step > 3 %}<i class="bi bi-check"></i>{% else %}3{% endif %}
                    </div>
                    <div class="step-content {% if experiment.current_step == 3 %}active{% elif experiment.current_step < 3 %}disabled{% endif %}">
                        拧下螺丝
                    </div>
                </div>
                
                <div class="step-item">
                    <div class="step-number {% if experiment.current_step == 4 %}active{% elif experiment.current_step > 4 %}completed{% endif %}">
                        {% if experiment.current_step > 4 %}<i class="bi bi-check"></i>{% else %}4{% endif %}
                    </div>
                    <div class="step-content {% if experiment.current_step == 4 %}active{% elif experiment.current_step < 4 %}disabled{% endif %}">
                        放入盒子
                    </div>
                </div>
                
                <div class="step-item">
                    <div class="step-number {% if experiment.current_step == 5 %}active{% elif experiment.current_step > 5 %}completed{% endif %}">
                        {% if experiment.current_step > 5 %}<i class="bi bi-check"></i>{% else %}5{% endif %}
                    </div>
                    <div class="step-content {% if experiment.current_step == 5 %}active{% elif experiment.current_step < 5 %}disabled{% endif %}">
                        实验完成
                    </div>
                </div>
            </div>
            
            <div>
                <h4 class="mb-3">操作说明</h4>
                <div class="card">
                    <div class="card-body">
                        <p>当前步骤：<strong>{{ experiment.get_current_step_display }}</strong></p>
                        
                        <div>
                            {% if experiment.current_step == 1 %}
                                <div class="instruction highlight">
                                    <p><strong>定位操作：</strong>用鼠标<strong>按住拖动</strong>机械臂底座，将其移动到螺丝附近的合适位置。</p>
                                    <p>左键拖动可移动底座位置，按住Shift键拖动可旋转底座。您还可以拖动机械臂的其他关节以调整套筒的位置。</p>
                                    <p>机械臂套筒朝下但不会触碰桌面，需要将套筒部分悬停在螺丝钉上方才能完成此步骤。</p>
                                </div>
                            {% elif experiment.current_step == 2 %}
                                <div class="instruction highlight">
                                    <p><strong>扣住操作：</strong>用鼠标<strong>按住拖动</strong>机械臂套筒，先将其旋转向下对准螺丝，然后移动到螺丝头部上方。</p>
                                    <p>套筒需要正确朝向螺丝并足够接近，才能稳固套住螺丝。</p>
                                </div>
                            {% elif experiment.current_step == 3 %}
                                <!-- 左侧：只保留实时力数据可视化和操作说明，不包含参数输入 -->
                                <div class="mb-4">
                                    <h5>实时力数据可视化</h5>
                                    <div class="force-visualization-container" style="text-align: center; background-color: #f8f9fa; padding: 10px; border-radius: 5px;">
                                        <img id="force-visualization-image" src="" alt="力数据可视化" style="max-width: 100%; height: auto; border: 1px solid #ddd; border-radius: 4px;">
                                    </div>
                                </div>
                                
                                <div class="instruction highlight mb-4">
                                    <p>在这个步骤中，您需要操作机械臂将紧固件（螺丝）沿逆时针方向旋转以拧出。</p>
                                    
                                    
                                    <p><button id="auto-unscrew-btn-left" class="btn btn-warning">自动拧出螺丝</button></p>
                                </div>
                            {% elif experiment.current_step == 4 %}
                                <div class="instruction highlight">
                                    <p><strong>移动操作：</strong>用鼠标<strong>按住拖动</strong>机械臂，将套住螺丝的套筒移动到收集盒上方，然后释放。</p>
                                    <p>确保螺丝准确移动到收集盒上方。当您将机械臂移动到收集盒上方后，点击"检查步骤"按钮，如果位置正确，将出现"释放螺丝"按钮，点击该按钮让螺丝平躺在黑色收集盒的上表面。</p>
                                </div>
                            {% elif experiment.current_step == 5 %}
                                <p>恭喜您成功完成实验！</p>
                                <p>您可以查看实验记录或返回首页。</p>
                            {% endif %}
                        </div>
                        
                        <div class="mt-4 d-grid gap-2">
                            <button id="check-step-btn-left" class="check-step-btn btn btn-primary">检查步骤</button>
                            
                            <!-- 添加释放螺丝按钮，初始隐藏 -->
                            <button id="release-screw-btn-left" class="release-screw-btn btn btn-warning" style="display: none;">
                                释放螺丝
                            </button>
                            
                            <form action="{% url 'experiment_step' experiment.id experiment.current_step %}" method="post" id="step-form-left">
                                {% csrf_token %}
                                <input type="hidden" name="step_result" id="step-result-left" value="pending">
                                <button type="submit" class="submit-step-btn btn btn-success w-100" style="display: none;">
                                    提交并继续
                                </button>
                            </form>
                        </div>
                        
                        <div id="feedback-message" class="feedback-message">
                            操作反馈将显示在这里
                        </div>
                    </div>
                </div>
            </div>
        </div>
        
        <div class="col-md-9">
            <div class="experiment-area">
                {% if experiment.status == 'completed' %}
                    <div class="text-center py-5">
                        <div class="mb-4">
                            <i class="bi bi-check-circle-fill text-success" style="font-size: 5rem;"></i>
                        </div>
                        <h3>实验已成功完成！</h3>
                        <p class="mb-4">您已成功完成了全部实验步骤，感谢参与。</p>
                        <div>
                            <a href="{% url 'experiment_history' %}" class="btn btn-primary me-2">查看实验记录</a>
                            <a href="{% url 'experiment_platform' %}" class="btn btn-outline-primary">再次实验</a>
                        </div>
                    </div>
                {% else %}
                    <div class="robot-view">
                        <canvas id="robot-canvas" class="robot-canvas"></canvas>
                        <div id="operation-hint" class="operation-hint"></div>
                    </div>
                    
                    <div class="control-panel">
                        <div class="control-title">实验步骤 {{ experiment.current_step }}: 
                            {% if experiment.current_step == 1 %}
                                定位螺丝
                            {% elif experiment.current_step == 2 %}
                                扣住螺丝
                            {% elif experiment.current_step == 3 %}
                                拧下螺丝
                            {% elif experiment.current_step == 4 %}
                                放入盒子
                            {% elif experiment.current_step == 5 %}
                                实验完成
                            {% endif %}
                        </div>
                        
                        <!-- 当前步骤说明 -->
                        {% if experiment.current_step == 1 %}
                            <div class="instruction highlight">
                                <p><strong>定位操作：</strong>用鼠标<strong>按住拖动</strong>机械臂底座，将其移动到螺丝附近的合适位置。</p>
                                <p>左键拖动可移动底座位置，按住Shift键拖动可旋转底座。您还可以拖动机械臂的其他关节以调整套筒的位置。</p>
                                <p>机械臂套筒朝下但不会触碰桌面，需要将套筒部分悬停在螺丝钉上方才能完成此步骤。</p>
                            </div>
                        {% elif experiment.current_step == 2 %}
                            <div class="instruction highlight">
                                <p><strong>扣住操作：</strong>用鼠标<strong>按住拖动</strong>机械臂套筒，先将其旋转向下对准螺丝，然后移动到螺丝头部上方。</p>
                                <p>套筒需要正确朝向螺丝并足够接近，才能稳固套住螺丝。</p>
                            </div>
                        {% elif experiment.current_step == 3 %}
                            <!-- 右侧：只保留参数输入，不包含力数据可视化 -->
                            <div class="instruction highlight mb-4">
                                <p>在这个步骤中，您需要操作机械臂将紧固件（螺丝）沿逆时针方向旋转以拧出。</p>
                                
                                <div class="mb-4">
                                    <h5>参数输入：</h5>
                                    <div class="row mb-3">
                                        <div class="col-md-4">
                                            <label class="form-label">螺栓规格</label>
                                            <select id="screw-size" class="form-select">
                                                <option value="M3">M3 (螺距: 0.5mm)</option>
                                                <option value="M4">M4 (螺距: 0.7mm)</option>
                                                <option value="M5">M5 (螺距: 0.8mm)</option>
                                                <option value="M6">M6 (螺距: 1mm)</option>
                                                <option value="M8">M8 (螺距: 1.25mm)</option>
                                                <option value="M10">M10 (螺距: 1.5mm)</option>
                                                <option value="M12">M12 (螺距: 1.75mm)</option>
                                                <option value="M14">M14 (螺距: 2mm)</option>
                                            </select>
                                        </div>
                                        <div class="col-md-4">
                                            <label class="form-label">电机转速 (r/min)</label>
                                            <select id="motor-speed" class="form-select">
                                                <option value="100">100</option>
                                                <option value="150">150</option>
                                                <option value="200">200</option>
                                            </select>
                                        </div>
                                        <div class="col-md-4">
                                            <label class="form-label">螺纹线数</label>
                                            <select id="thread-count" class="form-select">
                                                <option value="1">1</option>
                                                <option value="2">2</option>
                                            </select>
                                        </div>
                                    </div>
                                    <div class="row mb-3">
                                        <div class="col-md-6">
                                            <label class="form-label">提取速度 (mm/min)</label>
                                            <input type="number" id="user-extraction-speed" class="form-control" placeholder="输入您估计的提取速度" min="0" step="1">
                                        </div>
                                        <div class="col-md-6 d-flex align-items-end">
                                            <div id="extraction-speed-feedback" class="text-muted small"></div>
                                        </div>
                                    </div>
                                    <!-- 保留隐藏的span用于后台计算 -->
                                    <span id="extraction-speed" style="display: none;">0 mm/min</span>
                                </div>
                                
                                
                                <p><button id="auto-unscrew-btn-right" class="btn btn-warning">自动拧出螺丝</button></p>
                            </div>
                        {% elif experiment.current_step == 4 %}
                            <div class="instruction highlight">
                                <p><strong>移动操作：</strong>用鼠标<strong>按住拖动</strong>机械臂，将套住螺丝的套筒移动到收集盒上方，然后释放。</p>
                                <p>确保螺丝准确移动到收集盒上方。当您将机械臂移动到收集盒上方后，点击"检查步骤"按钮，如果位置正确，将出现"释放螺丝"按钮，点击该按钮让螺丝平躺在黑色收集盒的上表面。</p>
                            </div>
                        {% elif experiment.current_step == 5 %}
                            <p>恭喜您成功完成实验！</p>
                            <p>您可以查看实验记录或返回首页。</p>
                        {% endif %}
                        
                        <div class="mt-4 d-grid gap-2">
                            <button id="check-step-btn-left" class="check-step-btn btn btn-primary">检查步骤</button>
                            
                            <!-- 添加释放螺丝按钮，初始隐藏 -->
                            <button id="release-screw-btn-right" class="release-screw-btn btn btn-warning" style="display: none;">
                                释放螺丝
                            </button>
                            
                            <form action="{% url 'experiment_step' experiment.id experiment.current_step %}" method="post" id="step-form-left">
                                {% csrf_token %}
                                <input type="hidden" name="step_result" id="step-result-left" value="pending">
                                <button type="submit" class="submit-step-btn btn btn-success w-100" style="display: none;">
                                    提交并继续
                                </button>
                            </form>
                        </div>
                        
                        <div id="feedback-message" class="feedback-message">
                            操作反馈将显示在这里
                        </div>
                    </div>
                {% endif %}
            </div>
        </div>
    </div>
</div>
{% endblock %}

{% block extra_js %}
<!-- 引入Three.js库 -->
<script src="{% static 'js/vendor/three.min.js' %}"></script>
<script src="{% static 'js/vendor/OrbitControls.js' %}"></script>
<script src="{% static 'js/vendor/GLTFLoader.js' %}"></script>
<!-- <script src="https://cdn.jsdelivr.net/npm/three-csg-ts@3.1.13/lib/umd/three-csg.min.js"></script> -->

<script>
    // 全局变量
    let scene, camera, renderer, controls;
    let raycaster, mouse;
    let robotArm = {};
    let table, screwBox, screw;
    let selectedObject = null;
    let dragging = false;
    let rotationMode = false;
    let currentStep = parseInt('{{ experiment.current_step }}');
    let stepCompleted = false;
    let SELECTED = null;
    let currentDraggingJoint = null;
    let previousMousePosition = new THREE.Vector2();
    let socketTipInitialY = 0; // 添加套筒初始Y坐标变量
    
    // 添加力数据可视化变量 - 现在只显示静态图片
    let forceVisualizationInterval = null;
    let currentImageIndex = 1;
    let totalImages = 100;
    
    // 保存上一步完成时的机械臂状态
    let savedArmState = {
        basePosition: null,
        baseRotation: null,
        upperArmRotation: null,
        elbowRotation: null,
        forearmRotation: null,
        wristRotation: null,
        handPosition: null,
        handRotation: null
    };
    
    // 场景参数
    const SCREW_POSITION = new THREE.Vector3(0, 0.5, 0);
    const BOX_POSITION = new THREE.Vector3(15, 2, -10);
    const ROBOT_INITIAL_POSITION = new THREE.Vector3(-15, 0, 5); // 将y坐标改回0，使底座紧贴桌面
    
    // 定义常量
    const POSITIONING_THRESHOLD = 8; // 第一步定位时，手部与螺丝的距离阈值
    const GRIPPING_THRESHOLD = 5; // 第二步抓取时，手部与螺丝的距离阈值（增大了阈值）
    const ROTATION_THRESHOLD = 7; // 第三步旋转量阈值 - 增大旋转量阈值
    const BOX_THRESHOLD = 5; // 第四步放入盒子的距离阈值
    const EXTRACTION_SPEED_THRESHOLD = 0.25; // 提取速度差异阈值（25%）
    
    // 碎屑粒子系统
    let debrisParticles = null;
    let debrisSystem = null;
    
    // 初始化3D场景
    function init() {
        // 创建场景
        scene = new THREE.Scene();
        scene.background = new THREE.Color(0x222222);
        
        // 创建相机
        camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
        camera.position.set(0, 30, 30);
        camera.lookAt(0, 0, 0);
        
        // 创建渲染器
        const container = document.getElementById('robot-canvas');
        if (!container) {
            console.error("找不到robot-canvas元素！无法创建渲染器");
            return;
        }
        
        console.log("找到canvas元素:", container);
        
        // 检查canvas尺寸
        console.log("Canvas尺寸:", container.clientWidth, container.clientHeight);
        
        // 确保canvas有合适的尺寸
        if (container.clientWidth === 0 || container.clientHeight === 0) {
            console.warn("Canvas尺寸为0，设置默认尺寸");
            container.style.width = '100%';
            container.style.height = '400px';
        }
        
        // 创建WebGL渲染器
        try {
            renderer = new THREE.WebGLRenderer({ 
                antialias: true, 
                canvas: container,
                alpha: true
            });
            renderer.setSize(container.clientWidth, container.clientHeight);
            renderer.shadowMap.enabled = true;
            console.log("渲染器创建成功");
        } catch (error) {
            console.error("创建渲染器失败:", error);
            return;
        }
        
        // 添加光照
        setupLighting();
        
        // 添加轨道控制器
        controls = new THREE.OrbitControls(camera, renderer.domElement);
        controls.enableDamping = true;
        controls.dampingFactor = 0.25;
        controls.enableZoom = true;
        controls.autoRotate = false;
        controls.maxPolarAngle = Math.PI / 2; // 限制视角不能低于地平面
        
        // 配置控制器鼠标按钮 - 保留右键拖动和滚轮缩放功能
        controls.mouseButtons = {
            LEFT: null,  // 禁用左键拖动视角
            MIDDLE: THREE.MOUSE.DOLLY,  // 中键缩放
            RIGHT: THREE.MOUSE.ROTATE  // 右键旋转视角
        };
        
        // 启用控制器，但仅用于右键和滚轮
        controls.enabled = true;
        
        // 设置射线检测器
        raycaster = new THREE.Raycaster();
        mouse = new THREE.Vector2();
        
        // 创建场景元素
        createEnvironment(); // 创建桌子和收集盒
        createScrew(); // 创建螺丝
        createRobotArm(); // 创建机械臂
        
        // 添加事件监听
        setupEventListeners();
        
        // 启动动画循环
        animate();
        
        // 根据当前步骤设置场景
        setupSceneForStep(currentStep);
        
        // 显示操作提示
        showOperationHint();
        
        // 强制更新机械臂的矩阵，确保所有部件正确连接
        if (robotArm && robotArm.group) {
            robotArm.group.updateMatrix();
            robotArm.group.updateMatrixWorld(true);
            
            if (robotArm.upperArm) {
                robotArm.upperArm.updateMatrix();
                robotArm.upperArm.updateMatrixWorld(true);
            }
            
            if (robotArm.elbow) {
                robotArm.elbow.updateMatrix();
                robotArm.elbow.updateMatrixWorld(true);
            }
            
            if (robotArm.forearm) {
                robotArm.forearm.updateMatrix();
                robotArm.forearm.updateMatrixWorld(true);
            }
            
            if (robotArm.wrist) {
                robotArm.wrist.updateMatrix();
                robotArm.wrist.updateMatrixWorld(true);
            }
            
            if (robotArm.hand) {
                robotArm.hand.updateMatrix();
                robotArm.hand.updateMatrixWorld(true);
            }
        }
        
        // 添加调试信息
        console.log("初始化完成");
        console.log("当前步骤:", currentStep);
        console.log("机械臂对象:", robotArm);
        console.log("机械臂组:", robotArm.group);
        console.log("机械臂底座:", robotArm.base);
        console.log("上臂:", robotArm.upperArm);
        console.log("手部:", robotArm.hand);
    }
    
    // 设置场景光照
    function setupLighting() {
        // 环境光
        const ambientLight = new THREE.AmbientLight(0xffffff, 0.5);
        scene.add(ambientLight);
        
        // 主方向光
        const mainLight = new THREE.DirectionalLight(0xffffff, 0.8);
        mainLight.position.set(10, 30, 20);
        mainLight.castShadow = true;
        mainLight.shadow.camera.left = -30;
        mainLight.shadow.camera.right = 30;
        mainLight.shadow.camera.top = 30;
        mainLight.shadow.camera.bottom = -30;
        mainLight.shadow.camera.far = 100;
        mainLight.shadow.mapSize.width = 1024;
        mainLight.shadow.mapSize.height = 1024;
        scene.add(mainLight);
        
        // 辅助光源
        const fillLight = new THREE.DirectionalLight(0xffffff, 0.3);
        fillLight.position.set(-10, 20, -20);
        scene.add(fillLight);
    }
    
    // 创建环境（桌子和收集盒）
    function createEnvironment() {
        // 创建桌面
        const tableGeometry = new THREE.BoxGeometry(60, 2, 40);
        const tableMaterial = new THREE.MeshStandardMaterial({ 
            color: 0x8B4513,
            roughness: 0.7, 
            metalness: 0.1
        });
        table = new THREE.Mesh(tableGeometry, tableMaterial);
        table.position.y = -1;
        table.receiveShadow = true;
        scene.add(table);
        
        // 添加桌面纹理
        const tableTopGeometry = new THREE.PlaneGeometry(60, 40);
        const tableTopMaterial = new THREE.MeshStandardMaterial({
            color: 0x996633,
            roughness: 0.6,
            metalness: 0.1
        });
        const tableTop = new THREE.Mesh(tableTopGeometry, tableTopMaterial);
        tableTop.rotation.x = -Math.PI / 2;
        tableTop.position.y = 0.01; // 稍微高于桌面
        tableTop.receiveShadow = true;
        scene.add(tableTop);
        
        // 创建地面
        const floorGeometry = new THREE.PlaneGeometry(120, 120);
        const floorMaterial = new THREE.MeshStandardMaterial({ 
            color: 0x444444,
            roughness: 0.9,
            metalness: 0.1
        });
        const floor = new THREE.Mesh(floorGeometry, floorMaterial);
        floor.rotation.x = -Math.PI / 2;
        floor.position.y = -10;
        floor.receiveShadow = true;
        scene.add(floor);
        
        // 创建螺丝收集盒
        const boxGroup = new THREE.Group();
        
        // 盒子底座
        const boxBaseGeometry = new THREE.BoxGeometry(10, 3, 8);
        const boxMaterial = new THREE.MeshStandardMaterial({ 
            color: 0x555555,
            roughness: 0.4,
            metalness: 0.6
        });
        const boxBase = new THREE.Mesh(boxBaseGeometry, boxMaterial);
        boxBase.position.y = 1.5;
        boxBase.castShadow = true;
        boxBase.receiveShadow = true;
        boxGroup.add(boxBase);
        
        // 盒子内部
        const boxInnerGeometry = new THREE.BoxGeometry(9, 2, 7);
        const boxInnerMaterial = new THREE.MeshStandardMaterial({ 
            color: 0x333333,
            roughness: 0.2,
            metalness: 0.3
        });
        const boxInner = new THREE.Mesh(boxInnerGeometry, boxInnerMaterial);
        boxInner.position.y = 2;
        boxGroup.add(boxInner);
        
        // 盒子标签
        const boxLabelGeometry = new THREE.PlaneGeometry(4, 1.5);
        const boxLabelMaterial = new THREE.MeshStandardMaterial({ 
            color: 0xEEEEEE,
            roughness: 0.3,
            metalness: 0
        });
        const boxLabel = new THREE.Mesh(boxLabelGeometry, boxLabelMaterial);
        boxLabel.position.set(0, 2.5, 4.01);
        boxLabel.rotation.x = 0;
        boxGroup.add(boxLabel);
        
        boxGroup.position.copy(BOX_POSITION);
        screwBox = boxGroup;
        scene.add(screwBox);
    }
    
    // 创建螺丝
    function createScrew() {
        const screwGroup = new THREE.Group();
        
        // 螺丝头
        const screwHeadGeometry = new THREE.CylinderGeometry(1.2, 1.2, 0.5, 6);
        const screwMaterial = new THREE.MeshStandardMaterial({ 
            color: 0x8A8A8A, 
            roughness: 0.3, 
            metalness: 0.8 
        });
        const screwHead = new THREE.Mesh(screwHeadGeometry, screwMaterial);
        screwHead.position.y = 0.25;
        screwHead.castShadow = true;
        screwHead.receiveShadow = true;
        screwGroup.add(screwHead);
        
        // 螺丝头十字槽
        const slotWidth = 0.8;
        const slotHeight = 0.2;
        const slotDepth = 0.3;
        
        const slot1Geometry = new THREE.BoxGeometry(slotWidth, slotHeight, slotDepth);
        const slot1 = new THREE.Mesh(slot1Geometry, 
            new THREE.MeshStandardMaterial({ color: 0x333333 }));
        slot1.position.y = 0.45;
        screwGroup.add(slot1);
        
        const slot2Geometry = new THREE.BoxGeometry(slotDepth, slotHeight, slotWidth);
        const slot2 = new THREE.Mesh(slot2Geometry, 
            new THREE.MeshStandardMaterial({ color: 0x333333 }));
        slot2.position.y = 0.45;
        screwGroup.add(slot2);
        
        // 添加螺丝体
        const screwBodyGeometry = new THREE.CylinderGeometry(0.8, 0.6, 3, 16);
        const screwBodyMaterial = new THREE.MeshStandardMaterial({ 
            color: 0x777777, 
            roughness: 0.4, 
            metalness: 0.7 
        });
        const screwBody = new THREE.Mesh(screwBodyGeometry, screwBodyMaterial);
        screwBody.position.y = -1.5; // 位于螺丝头下方
        screwBody.castShadow = true;
        screwBody.receiveShadow = true;
        screwGroup.add(screwBody);
        
        // 添加螺纹
        const threadCount = 8;
        const threadRadius = 0.85;
        const threadThickness = 0.1;
        
        for (let i = 0; i < threadCount; i++) {
            const y = -0.2 - (i * 0.35);
            const threadGeometry = new THREE.TorusGeometry(threadRadius, threadThickness, 8, 16);
            const thread = new THREE.Mesh(threadGeometry, screwBodyMaterial);
            thread.position.y = y;
            thread.rotation.x = Math.PI / 2;
            screwGroup.add(thread);
        }
        
        // 创建桌子上的螺丝孔
        const holeGeometry = new THREE.CylinderGeometry(0.8, 0.8, 0.2, 16);
        const holeMaterial = new THREE.MeshStandardMaterial({ color: 0x222222 });
        const hole = new THREE.Mesh(holeGeometry, holeMaterial);
        hole.position.copy(SCREW_POSITION);
        hole.position.y = 0.01;
        scene.add(hole);
        
        // 设置螺丝属性和位置
        screwGroup.userData = {
            type: 'screw',
            originalPosition: SCREW_POSITION.clone(),
            isRemoved: false,
            rotationAmount: 0 // 跟踪总旋转量
        };
        
        screwGroup.position.copy(SCREW_POSITION);
        screw = screwGroup;
        scene.add(screw);
    }
    
    // 创建机械臂
    function createRobotArm() {
        // 创建机械臂组
        const robotGroup = new THREE.Group();
        
        // 材质定义
        const metalMaterial = new THREE.MeshStandardMaterial({ 
            color: 0x4682B4, 
            roughness: 0.3, 
            metalness: 0.7 
        });
        
        const darkMetalMaterial = new THREE.MeshStandardMaterial({ 
            color: 0x2A4B7C, 
            roughness: 0.3, 
            metalness: 0.7 
        });
        
        const jointMaterial = new THREE.MeshStandardMaterial({ 
            color: 0x4169E1, 
            roughness: 0.2, 
            metalness: 0.8 
        });
        
        const accentMaterial = new THREE.MeshStandardMaterial({ 
            color: 0x2F4F4F, 
            roughness: 0.4, 
            metalness: 0.6 
        });
        
        const toolMaterial = new THREE.MeshStandardMaterial({ 
            color: 0x7C7C7C, 
            roughness: 0.4, 
            metalness: 0.7 
        });
        
        //--------------------------------------
        // 1. 底座部分 - 可拖动部分
        //--------------------------------------
        const baseGroup = new THREE.Group();
        baseGroup.userData = { 
            type: 'robot_base',
            draggable: true
        };
        
        // 底座底部
        const baseBottomGeometry = new THREE.CylinderGeometry(5.5, 6, 1, 32);
        const baseBottom = new THREE.Mesh(baseBottomGeometry, darkMetalMaterial);
        baseBottom.position.y = 0.5;
        baseBottom.castShadow = true;
        baseBottom.receiveShadow = true;
        baseGroup.add(baseBottom);
        
        // 底座主体
        const baseGeometry = new THREE.CylinderGeometry(4.5, 5.5, 2, 32);
        const base = new THREE.Mesh(baseGeometry, metalMaterial);
        base.position.y = 2;
        base.castShadow = true;
        base.receiveShadow = true;
        baseGroup.add(base);
        
        // 底座上部
        const baseTopGeometry = new THREE.CylinderGeometry(3.8, 4.5, 1, 32);
        const baseTop = new THREE.Mesh(baseTopGeometry, darkMetalMaterial);
        baseTop.position.y = 3.5;
        baseTop.castShadow = true;
        baseTop.receiveShadow = true;
        baseGroup.add(baseTop);
        
        // 底座装饰和连接件
        const baseRingGeometry = new THREE.TorusGeometry(4, 0.3, 16, 32);
        const baseRing = new THREE.Mesh(baseRingGeometry, jointMaterial);
        baseRing.position.y = 2.5;
        baseRing.rotation.x = Math.PI / 2;
        baseGroup.add(baseRing);
        
        // 添加连接到转盘的中心柱
        const centerColumnGeometry = new THREE.CylinderGeometry(2.5, 3, 1.5, 16);
        const centerColumn = new THREE.Mesh(centerColumnGeometry, metalMaterial);
        centerColumn.position.y = 4.5;
        centerColumn.castShadow = true;
        centerColumn.receiveShadow = true;
        baseGroup.add(centerColumn);
        
        // 添加旋转台
        const rotatingPlatformGeometry = new THREE.CylinderGeometry(2.8, 2.8, 0.7, 32);
        const rotatingPlatform = new THREE.Mesh(rotatingPlatformGeometry, jointMaterial);
        rotatingPlatform.position.y = 5.5;
        rotatingPlatform.castShadow = true;
        rotatingPlatform.receiveShadow = true;
        baseGroup.add(rotatingPlatform);
        
        // 添加旋转台上的装饰螺栓
        for (let i = 0; i < 6; i++) {
            const angle = (i / 6) * Math.PI * 2;
            const boltGeometry = new THREE.CylinderGeometry(0.2, 0.2, 0.2, 8);
            const bolt = new THREE.Mesh(boltGeometry, accentMaterial);
            bolt.position.set(
                Math.cos(angle) * 2.3,
                5.7,
                Math.sin(angle) * 2.3
            );
            baseGroup.add(bolt);
        }
        
        //--------------------------------------
        // 2. 肩部和旋转连接件
        //--------------------------------------
        // 肩部支架
        const shoulderBracketGeometry = new THREE.BoxGeometry(5, 1.5, 3.5);
        const shoulderBracket = new THREE.Mesh(shoulderBracketGeometry, darkMetalMaterial);
        shoulderBracket.position.y = 6.5;
        shoulderBracket.castShadow = true;
        shoulderBracket.receiveShadow = true;
        baseGroup.add(shoulderBracket);
        
        // 肩部转轴连接器
        const shoulderAxisGeometry = new THREE.CylinderGeometry(1, 1, 5.5, 16);
        const shoulderAxis = new THREE.Mesh(shoulderAxisGeometry, jointMaterial);
        shoulderAxis.rotation.z = Math.PI / 2;
        shoulderAxis.position.set(0, 6.8, 0);
        shoulderAxis.castShadow = true;
        shoulderAxis.receiveShadow = true;
        baseGroup.add(shoulderAxis);
        
        // 肩部轴承盖
        const shoulderCapGeometry = new THREE.CylinderGeometry(1.2, 1.2, 0.4, 16);
        const shoulderCapLeft = new THREE.Mesh(shoulderCapGeometry, metalMaterial);
        shoulderCapLeft.rotation.z = Math.PI / 2;
        shoulderCapLeft.position.set(-2.5, 6.8, 0);
        baseGroup.add(shoulderCapLeft);
        
        const shoulderCapRight = new THREE.Mesh(shoulderCapGeometry, metalMaterial);
        shoulderCapRight.rotation.z = Math.PI / 2;
        shoulderCapRight.position.set(2.5, 6.8, 0);
        baseGroup.add(shoulderCapRight);
        
        baseGroup.position.y = 0;
        robotGroup.add(baseGroup);
        robotArm.base = baseGroup;
        scene.add(robotGroup);
        
        //--------------------------------------
        // 3. 上臂和液压系统
        //--------------------------------------
        const upperArmGroup = new THREE.Group();
        upperArmGroup.userData = { 
            type: 'robot_upperArm',
            draggable: true
        };
        
        // 上臂外壳主体
        const armCoverGeometry = new THREE.BoxGeometry(1.6, 7, 2.5);
        const armCover = new THREE.Mesh(armCoverGeometry, metalMaterial);
        armCover.position.y = 3.5; 
        armCover.castShadow = true;
        armCover.receiveShadow = true;
        upperArmGroup.add(armCover);
        
        // 上臂内部结构
        const armInnerGeometry = new THREE.BoxGeometry(2.5, 6.5, 1.5);
        const armInner = new THREE.Mesh(armInnerGeometry, darkMetalMaterial);
        armInner.position.y = 3.5;
        armInner.castShadow = true;
        armInner.receiveShadow = true;
        upperArmGroup.add(armInner);
        
        // 上臂连接到肩部轴的环
        const shoulderConnectorGeometry = new THREE.TorusGeometry(1.2, 0.5, 16, 24);
        const shoulderConnector = new THREE.Mesh(shoulderConnectorGeometry, jointMaterial);
        shoulderConnector.rotation.x = Math.PI / 2;
        shoulderConnector.position.y = 0.2;
        upperArmGroup.add(shoulderConnector);
        
        // 上臂与肩部连接处的轴承盖
        const armConnectorCapGeometry = new THREE.CylinderGeometry(1.5, 1.5, 0.6, 16);
        const armConnectorCap = new THREE.Mesh(armConnectorCapGeometry, accentMaterial);
        armConnectorCap.position.y = 0.2;
        upperArmGroup.add(armConnectorCap);
        
        // 上臂装饰线条
        const armLineGeometry = new THREE.BoxGeometry(0.1, 6, 0.1);
        const armLine1 = new THREE.Mesh(armLineGeometry, accentMaterial);
        armLine1.position.set(0.7, 3.5, 1);
        upperArmGroup.add(armLine1);
        
        const armLine2 = new THREE.Mesh(armLineGeometry, accentMaterial);
        armLine2.position.set(0.7, 3.5, -1);
        upperArmGroup.add(armLine2);
        
        // 液压缸和连接件
        const hydraulicCylinderGeometry = new THREE.CylinderGeometry(0.5, 0.5, 6, 16);
        const hydraulicCylinder = new THREE.Mesh(hydraulicCylinderGeometry, toolMaterial);
        hydraulicCylinder.position.set(-1.2, 3.2, 0);
        hydraulicCylinder.rotation.z = Math.PI / 15;
        upperArmGroup.add(hydraulicCylinder);
        
        // 液压缸活塞
        const pistonGeometry = new THREE.CylinderGeometry(0.3, 0.3, 4, 16);
        const piston = new THREE.Mesh(pistonGeometry, accentMaterial);
        piston.position.set(-1.2, 3.8, 0);
        piston.rotation.z = Math.PI / 15;
        upperArmGroup.add(piston);
        
        // 液压缸连接点
        const hydraulicConnectorGeometry = new THREE.SphereGeometry(0.6, 16, 16);
        const hydraulicConnector1 = new THREE.Mesh(hydraulicConnectorGeometry, jointMaterial);
        hydraulicConnector1.position.set(-1.3, 0.5, 0);
        upperArmGroup.add(hydraulicConnector1);
        
        const hydraulicConnector2 = new THREE.Mesh(hydraulicConnectorGeometry, jointMaterial);
        hydraulicConnector2.position.set(-1, 6.2, 0);
        upperArmGroup.add(hydraulicConnector2);
        
        upperArmGroup.position.y = 6.5;
        upperArmGroup.rotation.x = -Math.PI / 6; // 默认角度
        robotGroup.add(upperArmGroup);
        robotArm.upperArm = upperArmGroup;
        
        //--------------------------------------
        // 4. 肘部关节和连接系统
        //--------------------------------------
        const elbowGroup = new THREE.Group();
        elbowGroup.position.y = 7; // 相对于上臂的顶部
        elbowGroup.userData = { 
            type: 'robot_elbow',
            draggable: true
        };
        upperArmGroup.add(elbowGroup);
        
        // 强制更新上臂矩阵，确保肘部位置正确
        upperArmGroup.updateMatrix();
        upperArmGroup.updateMatrixWorld(true);
        elbowGroup.updateMatrix();
        elbowGroup.updateMatrixWorld(true);
        
        // 肘部主体轴承
        const elbowJointGeometry = new THREE.CylinderGeometry(1, 1, 3.2, 32);
        const elbowJoint = new THREE.Mesh(elbowJointGeometry, jointMaterial);
        elbowJoint.rotation.z = Math.PI / 2;
        elbowJoint.castShadow = true;
        elbowJoint.receiveShadow = true;
        elbowGroup.add(elbowJoint);
        
        // 肘部内部连接架
        const elbowConnectorGeometry = new THREE.BoxGeometry(3.5, 1.2, 2.2);
        const elbowConnector = new THREE.Mesh(elbowConnectorGeometry, darkMetalMaterial);
        elbowConnector.position.y = 0.2;
        elbowGroup.add(elbowConnector);
        
        // 肘部轴承盖
        const elbowCapGeometry = new THREE.CylinderGeometry(1.2, 1.2, 0.4, 16);
        const elbowCapLeft = new THREE.Mesh(elbowCapGeometry, accentMaterial);
        elbowCapLeft.rotation.z = Math.PI / 2;
        elbowCapLeft.position.set(-1.8, 0, 0);
        elbowGroup.add(elbowCapLeft);
        
        const elbowCapRight = new THREE.Mesh(elbowCapGeometry, accentMaterial);
        elbowCapRight.rotation.z = Math.PI / 2;
        elbowCapRight.position.set(1.8, 0, 0);
        elbowGroup.add(elbowCapRight);
        
        // 装饰螺栓
        for (let i = 0; i < 4; i++) {
            const boltGeometry = new THREE.CylinderGeometry(0.15, 0.15, 0.3, 8);
            const bolt = new THREE.Mesh(boltGeometry, accentMaterial);
            bolt.position.set(
                (i < 2 ? -1 : 1),
                0.3,
                (i % 2 === 0 ? 0.8 : -0.8)
            );
            elbowGroup.add(bolt);
        }
        
        robotArm.elbow = elbowGroup;
        
        // 确保肘部连接正确
        elbowGroup.updateMatrix();
        elbowGroup.updateMatrixWorld(true);
        
        //--------------------------------------
        // 5. 前臂部分
        //--------------------------------------
        const forearmGroup = new THREE.Group();
        forearmGroup.userData = { 
            type: 'robot_forearm',
            draggable: true
        };
        
        // 前臂与肘部的连接环
        const forearmConnectorGeometry = new THREE.TorusGeometry(1, 0.4, 16, 24);
        const forearmConnector = new THREE.Mesh(forearmConnectorGeometry, jointMaterial);
        forearmConnector.rotation.x = Math.PI / 2;
        forearmConnector.position.y = 0.2; 
        forearmGroup.add(forearmConnector);
        
        // 前臂主体
        const forearmGeometry = new THREE.BoxGeometry(1.8, 5, 1.8);
        const forearm = new THREE.Mesh(forearmGeometry, metalMaterial);
        forearm.position.y = 2.5;
        forearm.castShadow = true;
        forearm.receiveShadow = true;
        forearmGroup.add(forearm);
        
        // 前臂装饰环
        for (let i = 0; i < 3; i++) {
            const ringGeometry = new THREE.TorusGeometry(0.95, 0.1, 16, 24);
            const ring = new THREE.Mesh(ringGeometry, accentMaterial);
            ring.rotation.x = Math.PI / 2;
            ring.position.y = 1 + i * 1.5;
            forearmGroup.add(ring);
        }
        
        // 前臂上的线缆管道
        const cableGeometry = new THREE.CylinderGeometry(0.3, 0.3, 5, 8);
        const cable = new THREE.Mesh(cableGeometry, darkMetalMaterial);
        cable.position.set(0.6, 2.5, 0.6);
        forearmGroup.add(cable);
        
        // 前臂连接到腕部的接头
        const wristConnectorGeometry = new THREE.BoxGeometry(2, 1, 2.2);
        const wristConnector = new THREE.Mesh(wristConnectorGeometry, darkMetalMaterial);
        wristConnector.position.y = 5;
        forearmGroup.add(wristConnector);
        
        // 设置前臂位置
        forearmGroup.position.y = 0.8; // 位于肘部关节上方
        forearmGroup.rotation.x = -Math.PI / 4; // 默认角度
        elbowGroup.add(forearmGroup);
        robotArm.forearm = forearmGroup;
        
        // 强制更新肘部矩阵，确保前臂位置正确
        elbowGroup.updateMatrix();
        elbowGroup.updateMatrixWorld(true);
        forearmGroup.updateMatrix();
        forearmGroup.updateMatrixWorld(true);
        
        //--------------------------------------
        // 6. 腕部关节系统
        //--------------------------------------
        const wristGroup = new THREE.Group();
        wristGroup.position.y = 5; // 前臂端部
        wristGroup.userData = { 
            type: 'robot_wrist',
            draggable: true
        };
        forearmGroup.add(wristGroup);
        
        // 腕部轴承
        const wristJointGeometry = new THREE.CylinderGeometry(0.8, 0.8, 2.8, 24);
        const wristJoint = new THREE.Mesh(wristJointGeometry, jointMaterial);
        wristJoint.rotation.z = Math.PI / 2;
        wristJoint.castShadow = true;
        wristJoint.receiveShadow = true;
        wristGroup.add(wristJoint);
        
        // 腕部轴承盖
        const wristCapGeometry = new THREE.CylinderGeometry(0.9, 0.9, 0.3, 16);
        const wristCapLeft = new THREE.Mesh(wristCapGeometry, accentMaterial);
        wristCapLeft.rotation.z = Math.PI / 2;
        wristCapLeft.position.set(-1.5, 0, 0);
        wristGroup.add(wristCapLeft);
        
        const wristCapRight = new THREE.Mesh(wristCapGeometry, accentMaterial);
        wristCapRight.rotation.z = Math.PI / 2;
        wristCapRight.position.set(1.5, 0, 0);
        wristGroup.add(wristCapRight);
        
        // 腕部旋转接口
        const wristFlange = new THREE.Mesh(
            new THREE.CylinderGeometry(1.2, 1.2, 0.8, 24),
            darkMetalMaterial
        );
        wristFlange.position.y = 1;
        wristGroup.add(wristFlange);
        
        // 连接到工具的适配器
        const toolAdapter = new THREE.Mesh(
            new THREE.CylinderGeometry(0.9, 1.1, 1, 16),
            metalMaterial
        );
        toolAdapter.position.y = 1.9;
        wristGroup.add(toolAdapter);
        
        robotArm.wrist = wristGroup;
        
        //--------------------------------------
        // 7. 末端工具（万能套筒） - 可拖动、可旋转部分
        //--------------------------------------
        const toolGroup = new THREE.Group();
        toolGroup.userData = { 
            type: 'robot_hand',
            draggable: true,
            rotatable: true
        };
        
        // 工具连接法兰
        const toolFlangeGeometry = new THREE.CylinderGeometry(0.8, 0.9, 0.8, 16);
        const toolFlange = new THREE.Mesh(toolFlangeGeometry, darkMetalMaterial);
        toolFlange.position.y = -0.8;
        toolFlange.castShadow = true;
        toolFlange.receiveShadow = true;
        toolGroup.add(toolFlange);
        
        // 工具主体
        const toolBodyGeometry = new THREE.BoxGeometry(1.5, 1, 1.5);
        const toolBody = new THREE.Mesh(toolBodyGeometry, darkMetalMaterial);
        toolBody.position.y = 0;
        toolBody.castShadow = true;
        toolBody.receiveShadow = true;
        toolGroup.add(toolBody);
        
        // 套筒底座
        const socketBaseGeometry = new THREE.CylinderGeometry(0.7, 0.7, 0.5, 16);
        const socketBase = new THREE.Mesh(socketBaseGeometry, metalMaterial);
        socketBase.position.z = 0.7;
        socketBase.position.y = 0;
        socketBase.rotation.x = Math.PI / 2;
        socketBase.castShadow = true;
        socketBase.receiveShadow = true;
        toolGroup.add(socketBase);
        
        // 套筒中间旋转部
        const socketMiddleGeometry = new THREE.CylinderGeometry(0.65, 0.65, 0.7, 16);
        const socketMiddle = new THREE.Mesh(socketMiddleGeometry, jointMaterial);
        socketMiddle.position.z = 1.3;
        socketMiddle.position.y = 0;
        socketMiddle.rotation.x = Math.PI / 2;
        socketMiddle.castShadow = true;
        socketMiddle.receiveShadow = true;
        toolGroup.add(socketMiddle);
        
        // 套筒主体
        const socketGeometry = new THREE.CylinderGeometry(1.5, 1.5, 1.8, 16); // 增大尺寸，使其能包住螺丝
        const socket = new THREE.Mesh(socketGeometry, toolMaterial);
        socket.position.z = 2.2;
        socket.position.y = 0;
        socket.rotation.x = Math.PI / 2;
        socket.castShadow = true;
        socket.receiveShadow = true;
        toolGroup.add(socket);
        
        // 套筒内部（用于套住螺丝的六角形空腔）
        const socketInnerGeometry = new THREE.CylinderGeometry(1.3, 1.3, 1.2, 16); // 改为圆形，更大尺寸
        const socketInner = new THREE.Mesh(
            socketInnerGeometry, 
            new THREE.MeshStandardMaterial({ 
                color: 0x222222,
                roughness: 0.5,
                metalness: 0.6
            })
        );
        socketInner.position.z = 2.8;
        socketInner.position.y = 0;
        socketInner.rotation.x = Math.PI / 2;
        toolGroup.add(socketInner);
        
        // 套筒装饰环
        const socketRingGeometry = new THREE.TorusGeometry(0.72, 0.15, 16, 32);
        const socketRing1 = new THREE.Mesh(socketRingGeometry, accentMaterial);
        socketRing1.position.z = 1.7;
        socketRing1.position.y = 0;
        socketRing1.rotation.y = Math.PI / 2;
        toolGroup.add(socketRing1);
        
        const socketRing2 = new THREE.Mesh(socketRingGeometry, accentMaterial);
        socketRing2.position.z = 2.7;
        socketRing2.position.y = 0;
        socketRing2.rotation.y = Math.PI / 2;
        toolGroup.add(socketRing2);
        
        // 工具上的装饰螺栓
        for (let i = 0; i < 4; i++) {
            const angle = (i / 4) * Math.PI * 2;
            const boltGeometry = new THREE.CylinderGeometry(0.15, 0.15, 0.3, 8);
            const bolt = new THREE.Mesh(boltGeometry, accentMaterial);
            bolt.position.set(
                Math.cos(angle) * 0.5,
                0.5,
                Math.sin(angle) * 0.5
            );
            toolGroup.add(bolt);
        }
        
        // 定位工具组
        toolGroup.position.y = 2.5; // 位于腕部上方
        toolGroup.position.z = 0;  // 初始不突出
        
        // 更新腕部矩阵，确保工具组位置正确
        wristGroup.updateMatrix();
        wristGroup.updateMatrixWorld(true);
        
        // 将工具组添加到腕部
        wristGroup.add(toolGroup);
        
        // 更新工具组矩阵
        toolGroup.updateMatrix();
        toolGroup.updateMatrixWorld(true);
        
        robotArm.hand = toolGroup;
        
        // 设置机械臂组属性
        robotGroup.userData = {
            type: 'robot_arm'
        };
        
        // 初始化isHoldingScrew属性
        robotArm.isHoldingScrew = false;
        
        // 将机械臂定位到初始位置
        robotGroup.position.copy(ROBOT_INITIAL_POSITION);
        
        // 重要：确保将robotGroup赋值给robotArm.group
        robotArm.group = robotGroup;
        
        // 确保机械臂已经添加到场景中
        scene.add(robotGroup);
        
        // 调试输出
        console.log("创建机械臂完成");
        console.log("机械臂底座:", robotArm.base);
        console.log("机械臂组:", robotArm.group);
    }
    
    // 根据当前步骤设置场景
    function setupSceneForStep(step) {
        // 重置所有状态
        resetStepState();
        
        // 根据步骤设置场景
        switch(step) {
            case 1: // 定位螺丝
                // 初始位置，等待用户拖动
                robotArm.group.position.copy(ROBOT_INITIAL_POSITION);
                
                // 套筒已经初始化在适当位置，朝下但不触碰桌面
                robotArm.hand.position.z = 0;
                robotArm.hand.rotation.x = -Math.PI/2; // 套筒朝下
                robotArm.forearm.rotation.x = -Math.PI/6; // 设置前臂角度使套筒不会触碰桌子
                
                // 根据机械臂初始位置，将机械臂姿态调整为套筒朝向螺丝的方向（仅水平方向）
                const screwDirection = new THREE.Vector3();
                screwDirection.subVectors(SCREW_POSITION, ROBOT_INITIAL_POSITION).normalize();
                robotArm.group.lookAt(SCREW_POSITION.x, ROBOT_INITIAL_POSITION.y, SCREW_POSITION.z);
                
                // 确保上臂角度合适
                robotArm.upperArm.rotation.x = -Math.PI / 3; // 调整上臂角度，使套筒悬空更高
                
                // 不调用updateRobotArmPose，让用户可以自由移动关节
                break;
                
            case 2: // 扣住螺丝
                // 尝试从localStorage中恢复保存的状态
                let storedState = localStorage.getItem('savedArmState');
                if (storedState) {
                    try {
                        let parsedState = JSON.parse(storedState);
                        // 使用保存的状态，不需要额外转换，因为我们保存的是普通对象
                        const restored = restoreArmState(parsedState);
                        if (restored) {
                            console.log('成功从localStorage恢复了机械臂状态');
                            // 更新操作提示，显示正确的第二步操作指引
                            showOperationHint();
                        } else {
                            console.warn('无法恢复保存的机械臂状态，将使用默认位置');
                            // 即使恢复失败也更新操作提示
                            showOperationHint();
                        }
                    } catch (e) {
                        console.error('解析保存的状态时出错:', e);
                        // 出错时也更新操作提示
                        showOperationHint();
                    }
                } else {
                    console.warn('未找到保存的机械臂状态，将使用默认位置');
                    // 未找到状态时也更新操作提示
                    showOperationHint();
                }
                
                // 仅重置步骤状态变量
                stepCompleted = false;
                break;
                
            case 3: // 拧下螺丝
                console.log('设置步骤3场景：拧下螺丝');
                
                // 重置套筒初始Y坐标
                socketTipInitialY = 0;
                
                // 从本地存储中恢复步骤二保存的机械臂状态
                let step2State = localStorage.getItem('step2ArmState');
                if (step2State) {
                    try {
                        let parsedState = JSON.parse(step2State);
                        // 使用步骤二保存的状态恢复机械臂位置
                        const restored = restoreArmState(parsedState);
                        if (restored) {
                            console.log('成功从localStorage恢复了步骤二的机械臂状态');
                            // 启用旋转模式
                            rotationMode = true;
                            
                            // 确保螺丝方向正确 - 垂直向下
                            if(screw) {
                                screw.rotation.set(0, 0, 0);
                                // 确保螺丝初始旋转量为0
                                screw.userData.rotationAmount = 0;
                            }
                        } else {
                            console.warn('无法恢复步骤二保存的机械臂状态，将使用默认位置');
                            // 套筒已扣住螺丝，等待用户旋转
                            robotArm.group.position.set(SCREW_POSITION.x, 0, SCREW_POSITION.z - 2);
                            robotArm.hand.position.z = 2; // 套筒向前伸出以对准螺丝
                            updateRobotArmPose();
                            rotationMode = true; // 启用旋转模式
                            
                            // 确保螺丝方向正确
                            if(screw) {
                                screw.rotation.set(0, 0, 0);
                                screw.userData.rotationAmount = 0;
                            }
                        }
                    } catch (e) {
                        console.error('解析保存的状态时出错:', e);
                        // 使用默认位置
                        robotArm.group.position.set(SCREW_POSITION.x, 0, SCREW_POSITION.z - 2);
                        robotArm.hand.position.z = 2; // 套筒向前伸出以对准螺丝
                        updateRobotArmPose();
                        rotationMode = true; // 启用旋转模式
                        
                        // 确保螺丝方向正确
                        if(screw) {
                            screw.rotation.set(0, 0, 0);
                            screw.userData.rotationAmount = 0;
                        }
                    }
                } else {
                    console.warn('未找到步骤二保存的机械臂状态，将使用默认位置');
                    // 使用默认位置
                    robotArm.group.position.set(SCREW_POSITION.x, 0, SCREW_POSITION.z - 2);
                    robotArm.hand.position.z = 2; // 套筒向前伸出以对准螺丝
                    updateRobotArmPose();
                    rotationMode = true; // 启用旋转模式
                    
                    // 确保螺丝方向正确
                    if(screw) {
                        screw.rotation.set(0, 0, 0);
                        screw.userData.rotationAmount = 0;
                    }
                }
                break;
                
            case 4: // 放入盒子
                console.log('设置步骤4场景：放入盒子');
                
                // 尝试从localStorage中恢复第三步保存的机械臂状态
                let step3State = localStorage.getItem('step3ArmState');
                if (!step3State) {
                    // 如果localStorage中没有，尝试从sessionStorage中恢复备份
                    step3State = sessionStorage.getItem('step3ArmState_backup');
                }
                
                if (step3State) {
                    try {
                        let parsedState = JSON.parse(step3State);
                        console.log('准备恢复的状态:', parsedState);
                        
                        // 先重置机械臂和螺丝的状态
                        robotArm.isHoldingScrew = false;
                        if (screw) {
                            screw.userData = {
                                type: 'screw',
                                originalPosition: SCREW_POSITION.clone(),
                                isRemoved: true,
                                rotationAmount: ROTATION_THRESHOLD
                            };
                            screw.rotation.set(0, 0, 0);
                        }
                        
                        // 使用第三步保存的状态恢复机械臂位置
                        const restored = restoreArmState(parsedState);
                        if (restored) {
                            console.log('成功从存储中恢复了步骤三的机械臂状态');
                            
                            // 确保螺丝处于正确状态
                            if (screw) {
                                // 确保螺丝垂直向下
                                screw.rotation.set(0, 0, 0);
                                
                                // 设置螺丝状态
                                screw.userData.isRemoved = true;
                                screw.userData.rotationAmount = ROTATION_THRESHOLD;
                                
                                // 如果状态中有保存螺丝的最终提升高度，使用它
                                if (parsedState.screwState && parsedState.screwState.liftAmount !== undefined) {
                                    screw.userData.finalLiftAmount = parsedState.screwState.liftAmount;
                                } else {
                                    // 否则使用默认计算
                                    screw.userData.finalLiftAmount = Math.min(3.5, ROTATION_THRESHOLD * 0.5);
                                }
                                
                                // 确保机械臂正确抓住螺丝
                                robotArm.isHoldingScrew = true;
                            }
                            
                            // 强制更新机械臂矩阵
                            robotArm.group.updateMatrix();
                            robotArm.group.updateMatrixWorld(true);
                            robotArm.upperArm.updateMatrix();
                            robotArm.upperArm.updateMatrixWorld(true);
                            robotArm.forearm.updateMatrix();
                            robotArm.forearm.updateMatrixWorld(true);
                            robotArm.wrist.updateMatrix();
                            robotArm.wrist.updateMatrixWorld(true);
                            robotArm.hand.updateMatrix();
                            robotArm.hand.updateMatrixWorld(true);
                            
                            // 最后更新螺丝位置
                            if (screw) {
                                updateScrewPosition();
                            }
                            
                            // 再次强制渲染
                            render();
                        } else {
                            console.warn('无法恢复保存的机械臂状态，将使用默认位置');
                            useDefaultStep4Position();
                        }
                    } catch (e) {
                        console.error('解析保存的状态时出错:', e);
                        useDefaultStep4Position();
                    }
                } else {
                    console.warn('未找到步骤三保存的机械臂状态，将使用默认位置');
                    useDefaultStep4Position();
                }
                break;
                
            case 5: // 实验完成
                // 实验已完成，自动设置为成功状态
                stepCompleted = true;
                break;
        }
    }
    
    // 重置步骤状态
    function resetStepState() {
        stepCompleted = false;
        rotationMode = false;
        
        // 清空反馈
        document.getElementById('feedback-message').style.display = 'none';
        
        // 如果不是步骤4，确保螺丝在原位
        if (currentStep !== 4 && screw) {
            if (!screw.userData.isRemoved) {
                screw.position.copy(SCREW_POSITION);
                screw.rotation.set(0, 0, 0);
                
                // 重置螺丝旋转量，除了步骤3（因为需要累加旋转量）
                if (currentStep !== 3) {
                    screw.userData.rotationAmount = 0;
                }
            }
        }
    }
    
    // 更新机械臂姿态
    function updateRobotArmPose() {
        // 如果当前步骤是第一步，且用户正在拖动某个关节，不要自动调整
        if (currentStep === 1 && currentDraggingJoint !== null) {
            // 如果机械臂抓住了螺丝，只更新螺丝位置
            if (robotArm.isHoldingScrew) {
                updateScrewPosition();
            }
            return; // 不调整机械臂的姿态
        }
        
        // 原有的姿态计算逻辑
        const armLength = 7; // 机械臂总长度
        const handPos = robotArm.hand.getWorldPosition(new THREE.Vector3());
        
        // 计算手部离机械臂基座的距离
        const basePos = robotArm.base.getWorldPosition(new THREE.Vector3());
        const distance = new THREE.Vector3().subVectors(handPos, basePos);
        
        // 归一化距离并映射到机械臂关节角度
        let normalizedDist = Math.min(distance.length() / (armLength * 1.2), 1);
        
        // 只有当不在拖动时才更新肩膀/上臂角度
        if (currentDraggingJoint !== 'upperArm') {
            // 计算肩膀角度(上臂抬起程度)，根据距离调整 
            const shoulderAngle = -Math.PI/6 - (normalizedDist * Math.PI/3);
            robotArm.upperArm.rotation.x = shoulderAngle;
        }
        
        // 只有当不在拖动时才更新肘部/前臂角度
        if (currentDraggingJoint !== 'forearm' && currentDraggingJoint !== 'elbow') {
            // 计算肘部角度(前臂抬起程度)，根据距离调整
            const elbowAngle = -Math.PI/6 - (normalizedDist * Math.PI/6);
            robotArm.forearm.rotation.x = elbowAngle;
        }
        
        // 如果机械臂抓住了螺丝，则更新螺丝位置
        if (robotArm.isHoldingScrew) {
            updateScrewPosition();
        }
    }
    
    // 更新螺丝位置的辅助函数
    function updateScrewPosition() {
        if (!robotArm.isHoldingScrew || !screw) return;
        
        // 获取手部的全局位置
        const handWorldPos = new THREE.Vector3();
        robotArm.hand.getWorldPosition(handWorldPos);
        
        // 获取手部的全局旋转
        const handWorldQuaternion = new THREE.Quaternion();
        robotArm.hand.getWorldQuaternion(handWorldQuaternion);
        
        // 计算套筒前端的位置（考虑套筒朝向）
        const socketDir = new THREE.Vector3(0, 0, 1).applyQuaternion(handWorldQuaternion);
        const socketTipPosition = handWorldPos.clone().add(
            socketDir.multiplyScalar(3) // 按套筒长度偏移，确保螺丝位于套筒前端
        );
        
        // 根据步骤不同处理螺丝位置
        if (currentStep === 3) {
            // 第三步中，螺丝位置只通过用户旋转时的代码逻辑来更新
            // 不在这里强制更新位置，避免位置突然改变
            
            // 只更新X和Z坐标，保持Y坐标由旋转逻辑控制
            screw.position.x = socketTipPosition.x;
            screw.position.z = socketTipPosition.z;
        } else {
            // 在其他步骤中，正常更新螺丝位置
            screw.position.copy(socketTipPosition);
        }
        
        // 在第三步和第四步中，保持螺丝垂直向下
        if (currentStep >= 3) {
            // 确保螺丝垂直向下
            screw.rotation.set(0, 0, 0);
        } else {
            // 在其他步骤中，让螺丝跟随套筒旋转
            screw.quaternion.copy(handWorldQuaternion);
            
            // 添加额外旋转，确保螺丝头朝向套筒内部
            const extraRotation = new THREE.Quaternion();
            extraRotation.setFromAxisAngle(new THREE.Vector3(0, 0, 1), Math.PI); // 旋转180度
            screw.quaternion.multiply(extraRotation);
        }
        
        // 在第四步中，确保螺丝始终保持已拧出状态
        if (currentStep === 4) {
            screw.userData.isRemoved = true;
            robotArm.isHoldingScrew = true;
            
            // 确保螺丝垂直向下
            screw.rotation.set(0, 0, 0);
        }
    }
    
    // 设置事件监听器
    function setupEventListeners() {
        const canvas = document.getElementById('robot-canvas');
        
        // 确保canvas存在
        if (!canvas) {
            console.error("找不到robot-canvas元素！");
            return;
        }
        
        console.log("为canvas元素绑定事件:", canvas);
        
        // 添加各种鼠标事件监听 - 直接使用canvas元素
        canvas.addEventListener('mousedown', onMouseDown, false);
        canvas.addEventListener('mousemove', onMouseMove, false);
        canvas.addEventListener('mouseup', onMouseUp, false);
        canvas.addEventListener('mouseleave', onMouseLeave, false);
        
        // 设置canvas样式确保可交互
        canvas.style.cursor = "pointer";
        
        // 窗口大小调整事件
        window.addEventListener('resize', onWindowResize, false);
        
        // 步骤检查按钮点击事件
        const checkStepButtons = document.querySelectorAll('.check-step-btn');
        checkStepButtons.forEach(button => {
            button.addEventListener('click', checkCurrentStep);
        });
        
        // 添加释放螺丝按钮点击事件
        const releaseButtons = document.querySelectorAll('.release-screw-btn');
        releaseButtons.forEach(button => {
            button.addEventListener('click', releaseScrew);
        });
        
        // 在表单提交前保存状态
        const stepForms = document.querySelectorAll('form[id^="step-form-"]');
        stepForms.forEach(form => {
            form.addEventListener('submit', function(e) {
                // 如果是第一步，保存状态
                if (currentStep === 1 && stepCompleted) {
                    saveArmState();
                    localStorage.setItem('savedArmState', JSON.stringify(savedArmState));
                    console.log('表单提交前保存机械臂状态:', savedArmState);
                }
                // 如果是第二步，保存状态
                else if (currentStep === 2 && stepCompleted) {
                    saveArmState();
                    localStorage.setItem('step2ArmState', JSON.stringify(savedArmState));
                    console.log('表单提交前保存步骤二机械臂状态:', savedArmState);
                }
                // 添加保存步骤三状态的逻辑
                else if (currentStep === 3 && stepCompleted) {
                    saveArmState();
                    localStorage.setItem('step3ArmState', JSON.stringify(savedArmState));
                    console.log('表单提交前保存步骤三机械臂状态:', savedArmState);
                }
            });
        });
    }
    
    // 鼠标按下处理
    function onMouseDown(event) {
        // 只处理左键点击，右键点击交给OrbitControls处理
        if (event.button !== 0) {
            return;
        }
        
        // 计算鼠标位置
        const canvas = document.getElementById('robot-canvas');
        const rect = canvas.getBoundingClientRect();
        
        // 更精确的鼠标坐标计算
        mouse.x = ((event.clientX - rect.left) / rect.width) * 2 - 1;
        mouse.y = -((event.clientY - rect.top) / rect.height) * 2 + 1;
        previousMousePosition.set(mouse.x, mouse.y);
        
        console.log("鼠标按下坐标:", mouse.x, mouse.y);
        console.log("开始射线检测");
        
        // 根据不同步骤，创建不同的可点击物体数组
        const objects = [];
        
        switch (currentStep) {
            case 1: // 定位螺丝 - 可拖动机械臂所有关节
                objects.push(robotArm.base); // 基座
                objects.push(robotArm.upperArm); // 上臂
                objects.push(robotArm.elbow); // 肘部
                objects.push(robotArm.forearm); // 前臂
                objects.push(robotArm.wrist); // 手腕
                objects.push(robotArm.hand); // 手部（套筒）
                break;
                
            case 2: // 扣住螺丝 - 允许移动更多关节以便精确扣住螺丝
                objects.push(robotArm.base); // 基座微调
                objects.push(robotArm.upperArm); // 上臂
                objects.push(robotArm.forearm); // 前臂
                objects.push(robotArm.wrist); // 手腕
                objects.push(robotArm.hand); // 手部（套筒）
                break;
                
            case 3: // 拧下螺丝 - 只能旋转套筒
                objects.push(robotArm.hand);
                break;
                
            case 4: // 放入盒子 - 允许移动机械臂所有关节
                objects.push(robotArm.base);     // 基座
                objects.push(robotArm.upperArm); // 上臂
                objects.push(robotArm.elbow);    // 肘部
                objects.push(robotArm.forearm);  // 前臂
                objects.push(robotArm.wrist);    // 手腕
                objects.push(robotArm.hand);     // 手部（套筒）
                break;
        }
        
        console.log("可交互对象:", objects);
        
        // 如果对象数组为空或有undefined，直接返回
        if (objects.length === 0 || objects.some(obj => !obj)) {
            console.error("可交互对象数组为空或含有undefined");
            return;
        }
        
        // 直接选择第一个对象作为初始选择，避免射线检测失败
        let directSelection = null;
        switch (currentStep) {
            case 1:
                directSelection = robotArm.base;
                currentDraggingJoint = 'base';
                break;
            case 2:
                directSelection = robotArm.hand;
                currentDraggingJoint = 'hand';
                break;
            case 3:
                directSelection = robotArm.hand;
                currentDraggingJoint = 'hand';
                break;
            case 4:
                // 为第四步也选择一个默认关节（不仅仅是基座）
                directSelection = robotArm.base;
                currentDraggingJoint = 'base';
                break;
        }
        
        // 尝试射线检测找到更精确的物体
        try {
            // 设置射线投射器
            raycaster.setFromCamera(mouse, camera);
            
            // 检测交叉对象
            const intersects = raycaster.intersectObjects(objects, true);
            
            console.log("鼠标按下 - 可交互对象数量:", objects.length, "交叉点数量:", intersects.length);
            
            if (intersects.length > 0) {
                // 找到最近的对象
                let selectedTarget = intersects[0].object;
                
                console.log("选中对象:", selectedTarget);
                
                // 向上查找父对象，直到找到userData中有draggable标记的对象
                while (selectedTarget && (!selectedTarget.userData || !selectedTarget.userData.draggable)) {
                    selectedTarget = selectedTarget.parent;
                    console.log("向上查找父对象:", selectedTarget);
                }
                
                // 如果找到可拖动对象
                if (selectedTarget && selectedTarget.userData && selectedTarget.userData.draggable) {
                    SELECTED = selectedTarget;
                    
                    // 根据选中的对象类型设置不同的拖动模式
                    if (selectedTarget === robotArm.base || selectedTarget.parent === robotArm.base) {
                        currentDraggingJoint = 'base';
                    } else if (selectedTarget === robotArm.upperArm || selectedTarget.parent === robotArm.upperArm) {
                        currentDraggingJoint = 'upperArm';
                    } else if (selectedTarget === robotArm.elbow || selectedTarget.parent === robotArm.elbow) {
                        currentDraggingJoint = 'elbow';
                    } else if (selectedTarget === robotArm.forearm || selectedTarget.parent === robotArm.forearm) {
                        currentDraggingJoint = 'forearm';
                    } else if (selectedTarget === robotArm.wrist || selectedTarget.parent === robotArm.wrist) {
                        currentDraggingJoint = 'wrist';
                    } else if (selectedTarget === robotArm.hand || selectedTarget.parent === robotArm.hand) {
                        currentDraggingJoint = 'hand';
                    }
                    
                    console.log('选中了: ' + currentDraggingJoint);
                    
                    // 设置鼠标指针样式为"抓取"
                    document.body.style.cursor = 'grabbing';
                } else {
                    console.log("未找到可拖动对象，使用直接选择");
                    // 如果射线检测失败，使用直接选择
                    SELECTED = directSelection;
                    console.log("直接选择:", currentDraggingJoint);
                    document.body.style.cursor = 'grabbing';
                }
            } else {
                console.log("没有交叉点，使用直接选择");
                // 如果射线检测失败，使用直接选择
                SELECTED = directSelection;
                console.log("直接选择:", currentDraggingJoint);
                document.body.style.cursor = 'grabbing';
            }
        } catch (error) {
            console.error("射线检测出错:", error);
            // 出错时使用直接选择
            SELECTED = directSelection;
            console.log("直接选择:", currentDraggingJoint);
            document.body.style.cursor = 'grabbing';
        }
    }
    
    // 鼠标移动处理
    function onMouseMove(event) {
        // 如果没有选择物体，直接返回
        if (SELECTED === null || currentDraggingJoint === null) return;

        // 更新鼠标位置 - 使用与onMouseDown相同的计算方式
        const canvas = document.getElementById('robot-canvas');
        const rect = canvas.getBoundingClientRect();
        const currentMouseX = ((event.clientX - rect.left) / rect.width) * 2 - 1;
        const currentMouseY = -((event.clientY - rect.top) / rect.height) * 2 + 1;
        
        // 计算鼠标移动距离
        const deltaX = currentMouseX - previousMousePosition.x;
        const deltaY = currentMouseY - previousMousePosition.y;
        
        // 仅当移动足够大时才处理
        if (Math.abs(deltaX) < 0.001 && Math.abs(deltaY) < 0.001) {
            return;
        }
        
        // 更新前记录位置
        previousMousePosition.set(currentMouseX, currentMouseY);
        
        // 添加调试输出
        console.log("鼠标移动:", deltaX, deltaY, "步骤:", currentStep, "当前拖动关节:", currentDraggingJoint);
        
        // 放大移动响应
        const movementMultiplier = 50; // 增大移动乘数
        
        // 根据当前步骤和选中的物体执行不同的移动逻辑
        try {
            if (currentStep === 1) {
                if (currentDraggingJoint === 'base') {
                    // 基座移动和旋转
                    // 左右移动鼠标调整X轴位置
                    robotArm.group.position.x += deltaX * movementMultiplier;
                    // 上下移动鼠标调整Z轴位置
                    robotArm.group.position.z -= deltaY * movementMultiplier;
                    
                    // 限制位置在桌面范围内
                    robotArm.group.position.x = Math.max(-25, Math.min(25, robotArm.group.position.x));
                    robotArm.group.position.z = Math.max(-15, Math.min(15, robotArm.group.position.z));
                    
                    // 如果按住Shift键，则旋转而不是移动
                    if (event.shiftKey) {
                        robotArm.group.rotation.y += deltaX * 4.0;
                    }
                    
                    console.log("底座移动到:", robotArm.group.position.x, robotArm.group.position.z);
                } else if (currentDraggingJoint === 'upperArm') {
                    // 上臂旋转，限制角度范围
                    robotArm.upperArm.rotation.x += deltaY * 4.0;
                    robotArm.upperArm.rotation.x = Math.max(-Math.PI/2, Math.min(-Math.PI/6, robotArm.upperArm.rotation.x));
                    console.log("上臂旋转:", robotArm.upperArm.rotation.x);
                } else if (currentDraggingJoint === 'forearm') {
                    // 前臂旋转，限制角度范围
                    robotArm.forearm.rotation.x += deltaY * 4.0;
                    robotArm.forearm.rotation.x = Math.max(-Math.PI/3, Math.min(Math.PI/4, robotArm.forearm.rotation.x));
                    console.log("前臂旋转:", robotArm.forearm.rotation.x);
                } else if (currentDraggingJoint === 'elbow') {
                    // 肘部旋转，以Z轴为轴心
                    robotArm.elbow.rotation.z += deltaX * 4.0;
                    robotArm.elbow.rotation.z = Math.max(-Math.PI/3, Math.min(Math.PI/3, robotArm.elbow.rotation.z));
                    console.log("肘部旋转:", robotArm.elbow.rotation.z);
                } else if (currentDraggingJoint === 'wrist') {
                    // 手腕旋转
                    robotArm.wrist.rotation.z += deltaX * 4.0;
                    robotArm.wrist.rotation.z = Math.max(-Math.PI/2, Math.min(Math.PI/2, robotArm.wrist.rotation.z));
                    
                    // 手腕上下倾斜
                    robotArm.wrist.rotation.x += deltaY * 4.0;
                    robotArm.wrist.rotation.x = Math.max(-Math.PI/2, Math.min(Math.PI/2, robotArm.wrist.rotation.x));
                    console.log("手腕旋转:", robotArm.wrist.rotation.x);
                } else if (currentDraggingJoint === 'hand') {
                    // 手部（套筒）旋转
                    robotArm.hand.rotation.z += deltaX * 4.0;
                    console.log("手部旋转:", robotArm.hand.rotation.z);
                }
                
                // 如果机械臂正在握住螺丝，更新螺丝位置
                if (robotArm.isHoldingScrew) {
                    updateScrewPosition();
                }
            }
            // 其他步骤的移动逻辑也需类似处理
            else if (currentStep === 2) {
                // 步骤2的移动逻辑 - 允许移动所有已定义的关节，便于精确定位
                if (currentDraggingJoint === 'base') {
                    // 基座微调 - 允许更小范围的移动
                    robotArm.group.position.x += deltaX * movementMultiplier * 0.5; // 降低灵敏度以便微调
                    robotArm.group.position.z -= deltaY * movementMultiplier * 0.5;
                    
                    // 限制位置在桌面范围内
                    robotArm.group.position.x = Math.max(-25, Math.min(25, robotArm.group.position.x));
                    robotArm.group.position.z = Math.max(-15, Math.min(15, robotArm.group.position.z));
                    
                    // 如果按住Shift键，则旋转而不是移动
                    if (event.shiftKey) {
                        robotArm.group.rotation.y += deltaX * 2.0; // 降低旋转灵敏度
                    }
                    
                    console.log("底座微调到:", robotArm.group.position.x, robotArm.group.position.z);
                } else if (currentDraggingJoint === 'upperArm') {
                    // 上臂旋转，用于调整套筒高度，限制角度范围
                    robotArm.upperArm.rotation.x += deltaY * 2.0;
                    robotArm.upperArm.rotation.x = Math.max(-Math.PI/2, Math.min(-Math.PI/12, robotArm.upperArm.rotation.x));
                    console.log("上臂微调旋转:", robotArm.upperArm.rotation.x);
                } else if (currentDraggingJoint === 'forearm') {
                    // 前臂旋转，用于调整套筒位置，限制角度范围
                    robotArm.forearm.rotation.x += deltaY * 2.0;
                    robotArm.forearm.rotation.x = Math.max(-Math.PI/3, Math.min(Math.PI/4, robotArm.forearm.rotation.x));
                    console.log("前臂微调旋转:", robotArm.forearm.rotation.x);
                } else if (currentDraggingJoint === 'wrist') {
                    // 手腕旋转，用于调整套筒朝向
                    robotArm.wrist.rotation.z += deltaX * 2.0;
                    robotArm.wrist.rotation.z = Math.max(-Math.PI/2, Math.min(Math.PI/2, robotArm.wrist.rotation.z));
                    
                    // 手腕上下倾斜，关键用于让套筒朝下对准螺丝
                    robotArm.wrist.rotation.x += deltaY * 2.0;
                    robotArm.wrist.rotation.x = Math.max(-Math.PI/2, Math.min(Math.PI/2, robotArm.wrist.rotation.x));
                    console.log("手腕微调旋转:", robotArm.wrist.rotation.x);
                } else if (currentDraggingJoint === 'hand') {
                    // 手部（套筒）旋转和前后移动，关键用于精确对准螺丝
                    // 左右移动鼠标旋转套筒
                    robotArm.hand.rotation.z += deltaX * 2.0;
                    
                    // 上下移动鼠标调整套筒前后位置
                    robotArm.hand.position.z += deltaY * 10.0;
                    robotArm.hand.position.z = Math.max(-2, Math.min(4, robotArm.hand.position.z));
                    
                    console.log("手部微调:", "旋转:", robotArm.hand.rotation.z, "位置:", robotArm.hand.position.z);
                }
            }
            else if (currentStep === 3) {
                // 步骤3的移动逻辑
                if (currentDraggingJoint === 'hand') {
                    // 旋转套筒
                    let rotationSpeed = 0.5;  // 增大旋转速度
                    let rotation = deltaX * rotationSpeed;
                    robotArm.hand.rotation.z += rotation;
                    
                    // 更新螺丝旋转
                    if (screw) {
                        // 更新螺丝的Z轴旋转，保持与套筒同步
                        screw.rotation.z = robotArm.hand.rotation.z;
                        
                        // 记录用户当前操作状态，避免结束时位置突变
                        screw.userData.userControlling = true;
                        
                        // 累加旋转量（只在逆时针旋转时）
                        if (deltaX < 0) {
                            if (!screw.userData.rotationAmount) {
                                screw.userData.rotationAmount = 0;
                            }
                            screw.userData.rotationAmount += Math.abs(rotation);
                            
                            // 螺丝上升 - 只有旋转量达到阈值才开始上升
                            if (screw.userData.rotationAmount > 0.5) {
                                let liftAmount = Math.min(3.5, screw.userData.rotationAmount * 0.5);
                                
                                // 平滑更新螺丝Y位置
                                screw.position.y = SCREW_POSITION.y + liftAmount;
                                
                                // 同时记录当前提升高度，以便在保存状态时使用
                                screw.userData.finalLiftAmount = liftAmount;
                                
                                // 不再让机械臂底座上升
                                // robotArm.group.position.y = liftAmount;
                                
                                // 计算前一帧和当前帧的提升差值
                                const prevLiftAmount = Math.min(3.5, (screw.userData.rotationAmount - rotateSpeed) * 0.5);
                                const liftDelta = liftAmount - prevLiftAmount;
                                
                                // 调整上臂角度，使套筒随螺丝钉上升 - 只应用增量变化
                                const adjustAmount = liftDelta * 0.06; // 角度调整系数，去掉负号使机械臂上升，减小调整系数
                                robotArm.upperArm.rotation.x += adjustAmount; // 增量调整
                                
                                // 同时微调前臂角度，保持套筒水平位置
                                robotArm.forearm.rotation.x += adjustAmount * 0.5; // 也改为同方向
                                
                                // 调整手腕角度，确保套筒始终朝向垂直向下
                                // 计算需要补偿的角度，以保持垂直向下
                                robotArm.wrist.rotation.x -= (adjustAmount + adjustAmount * 0.5);
                                
                                // 确保手部套筒始终保持垂直向下
                                robotArm.hand.rotation.x = -Math.PI / 2;
                                
                                // 确保每一帧螺丝都保持正确方向
                                screw.rotation.set(0, 0, 0);
                            }
                        }
                    }
                }
            }
            else if (currentStep === 4) {
                // 步骤4的移动逻辑
                if (currentDraggingJoint === 'base') {
                    // 基座移动和旋转
                    robotArm.group.position.x += deltaX * movementMultiplier;
                    robotArm.group.position.z -= deltaY * movementMultiplier;
                    
                    // 限制位置
                    robotArm.group.position.x = Math.max(-25, Math.min(25, robotArm.group.position.x));
                    robotArm.group.position.z = Math.max(-15, Math.min(15, robotArm.group.position.z));
                    
                    // 如果按住Shift键，则旋转而不是移动
                    if (event.shiftKey) {
                        robotArm.group.rotation.y += deltaX * 2.0;
                    }
                    
                    // 更新螺丝位置
                    if (robotArm.isHoldingScrew && screw) {
                        updateScrewPosition();
                    }
                } 
                // 添加对其他关节的控制逻辑
                else if (currentDraggingJoint === 'upperArm') {
                    // 上臂旋转
                    robotArm.upperArm.rotation.x += deltaY * 2.0;
                    robotArm.upperArm.rotation.x = Math.max(-Math.PI/2, Math.min(0, robotArm.upperArm.rotation.x));
                    
                    // 更新螺丝位置
                    if (robotArm.isHoldingScrew && screw) {
                        updateScrewPosition();
                    }
                }
                else if (currentDraggingJoint === 'forearm') {
                    // 前臂旋转
                    robotArm.forearm.rotation.x += deltaY * 2.0;
                    robotArm.forearm.rotation.x = Math.max(-Math.PI/3, Math.min(Math.PI/4, robotArm.forearm.rotation.x));
                    
                    // 更新螺丝位置
                    if (robotArm.isHoldingScrew && screw) {
                        updateScrewPosition();
                    }
                }
                else if (currentDraggingJoint === 'wrist') {
                    // 手腕旋转
                    robotArm.wrist.rotation.x += deltaY * 2.0;
                    robotArm.wrist.rotation.x = Math.max(-Math.PI/2, Math.min(Math.PI/2, robotArm.wrist.rotation.x));
                    
                    // 更新螺丝位置
                    if (robotArm.isHoldingScrew && screw) {
                        updateScrewPosition();
                    }
                }
                else if (currentDraggingJoint === 'hand') {
                    // 手部旋转（小幅度调整套筒朝向）
                    robotArm.hand.rotation.x += deltaY * 1.0;
                    robotArm.hand.rotation.x = Math.max(-Math.PI, Math.min(0, robotArm.hand.rotation.x));
                    
                    // 更新螺丝位置
                    if (robotArm.isHoldingScrew && screw) {
                        updateScrewPosition();
                    }
                }
            }

            // 强制渲染
            render();
            
            // 检查步骤进度
            checkStepProgress();
        }
        catch (error) {
            console.error("移动处理出错:", error);
        }
    }
    
    // 鼠标释放处理
    function onMouseUp(event) {
        // 添加调试输出
        console.log("鼠标释放 - 当前拖动关节:", currentDraggingJoint);
        
        // 如果当前是第三步，记录螺丝钉的最终位置和旋转，避免突然改变
        if (currentStep === 3 && screw && screw.userData.userControlling) {
            // 设置标志位表示用户不再控制
            screw.userData.userControlling = false;
            
            // 保存当前位置和旋转状态
            screw.userData.userSetPosition = screw.position.clone();
            screw.userData.userSetRotation = {
                x: screw.rotation.x,
                y: screw.rotation.y,
                z: screw.rotation.z
            };
            
            console.log("第三步鼠标释放 - 保存螺丝当前状态:", {
                位置: screw.userData.userSetPosition,
                旋转: screw.userData.userSetRotation,
                旋转量: screw.userData.rotationAmount
            });
        }
        
        // 重置鼠标样式
        document.body.style.cursor = 'auto';
        
        // 如果有选中的对象，检查步骤进度
        if (SELECTED !== null) {
            console.log("检查步骤进度");
            checkStepProgress();
        }
        
        // 重置选中状态
        SELECTED = null;
        currentDraggingJoint = null;
        
        // 强制渲染一次
        render();
    }
    
    // 窗口大小调整处理
    function onWindowResize() {
        const container = renderer.domElement;
        const width = container.clientWidth;
        const height = container.clientHeight;
        
        camera.aspect = width / height;
        camera.updateProjectionMatrix();
        
        renderer.setSize(width, height);
    }
    
    // 动画循环
    function animate() {
        requestAnimationFrame(animate);
        
        // 更新控制器
        if (controls && controls.enabled) {
            controls.update();
        }
        
        // 定期更新机械臂矩阵，确保所有部件正确连接
        if (robotArm && robotArm.group) {
            // 只在非拖动状态下更新矩阵，避免干扰用户操作
            if (currentDraggingJoint === null) {
                robotArm.group.updateMatrix();
                robotArm.group.updateMatrixWorld(true);
                
                if (robotArm.upperArm) {
                    robotArm.upperArm.updateMatrix();
                    robotArm.upperArm.updateMatrixWorld(true);
                }
                
                if (robotArm.elbow) {
                    robotArm.elbow.updateMatrix();
                    robotArm.elbow.updateMatrixWorld(true);
                }
                
                if (robotArm.forearm) {
                    robotArm.forearm.updateMatrix();
                    robotArm.forearm.updateMatrixWorld(true);
                }
                
                if (robotArm.wrist) {
                    robotArm.wrist.updateMatrix();
                    robotArm.wrist.updateMatrixWorld(true);
                }
                
                if (robotArm.hand) {
                    robotArm.hand.updateMatrix();
                    robotArm.hand.updateMatrixWorld(true);
                }
                
                // 如果机械臂抓住了螺丝，则更新螺丝位置
                if (robotArm.isHoldingScrew && screw) {
                    updateScrewPosition();
                }
            }
        }
        
        // 渲染场景
        render();
    }
    
    // 渲染场景
    function render() {
        renderer.render(scene, camera);
    }
    
    // 检查当前步骤进度
    function checkStepProgress() {
        switch(currentStep) {
            case 1: // 定位螺丝
                // 计算套筒前端与螺丝的距离
                const handPosStep1 = new THREE.Vector3();
                robotArm.hand.getWorldPosition(handPosStep1);
                
                // 计算套筒前端的位置（考虑套筒朝下）
                const socketDirection = new THREE.Vector3(0, 0, 1).applyQuaternion(
                    robotArm.hand.getWorldQuaternion(new THREE.Quaternion())
                );
                const socketTipPosition = handPosStep1.clone().add(
                    socketDirection.multiplyScalar(3) // 按套筒长度偏移
                );
                
                const handToScrewDistStep1 = socketTipPosition.distanceTo(SCREW_POSITION);
                
                // 判断套筒是否在螺丝上方的适当位置 - 放宽条件
                // 只要套筒大致位于螺丝上方即可，不需要特别精确
                const isAboveScrew = socketTipPosition.y > SCREW_POSITION.y && 
                                     Math.abs(socketTipPosition.x - SCREW_POSITION.x) < 8 &&
                                     Math.abs(socketTipPosition.z - SCREW_POSITION.z) < 8;
                
                // 只要套筒大致位于螺丝上方即可通过
                stepCompleted = handToScrewDistStep1 < POSITIONING_THRESHOLD * 2 && isAboveScrew;
                break;
                
            case 2: // 扣住螺丝
                // 计算手部与螺丝的距离
                const handPosition = new THREE.Vector3();
                robotArm.hand.getWorldPosition(handPosition);
                
                // 计算套筒前端的位置（考虑套筒朝向）
                const socketDir = new THREE.Vector3(0, 0, 1).applyQuaternion(
                    robotArm.hand.getWorldQuaternion(new THREE.Quaternion())
                );
                const socketTip = handPosition.clone().add(
                    socketDir.multiplyScalar(3) // 按套筒长度偏移
                );
                
                const handToScrewDistance = socketTip.distanceTo(SCREW_POSITION);
                
                // 检查套筒朝向 - 需要套筒朝下且对准螺丝
                const downVector = new THREE.Vector3(0, -1, 0);
                const handDirection = new THREE.Vector3(0, 0, 1).applyQuaternion(
                    robotArm.hand.getWorldQuaternion(new THREE.Quaternion())
                );
                const angleToDown = handDirection.angleTo(downVector);
                
                // 套筒需要更精确地扣住螺丝，距离更近，角度更准确
                const heightDiff = Math.abs(socketTip.y - SCREW_POSITION.y);
                stepCompleted = handToScrewDistance < GRIPPING_THRESHOLD && 
                               angleToDown < Math.PI/4 && // 放宽角度要求，从Math.PI/6改为Math.PI/4
                               heightDiff < 0.8; // 放宽高度差要求，从0.5改为0.8
                
                // 显示调试信息
                console.log("距离:", handToScrewDistance, "角度:", angleToDown * 180 / Math.PI, "高度差:", heightDiff);
                break;
                
            case 3: // 拧下螺丝
                // 检查总旋转量是否足够
                stepCompleted = screw.userData.rotationAmount >= ROTATION_THRESHOLD;
                
                // 当步骤3完成时，立即保存状态（不等待用户点击提交按钮）
                if (stepCompleted && !screw.userData.step3Saved) {
                    screw.userData.step3Saved = true;
                    
                    // 确保螺丝方向正确
                    screw.rotation.set(0, 0, 0);
                    
                    // 计算最终螺丝上升高度
                    const finalLiftAmount = Math.min(3.5, ROTATION_THRESHOLD * 0.5);
                    screw.userData.finalLiftAmount = finalLiftAmount;
                    
                    // 更新螺丝位置
                    screw.position.y = SCREW_POSITION.y + finalLiftAmount;
                    
                    // 确保机械臂正确抓住螺丝
                    robotArm.isHoldingScrew = true;
                    screw.userData.isRemoved = true;
                    
                    // 更新机械臂姿态以适应螺丝新的高度
                    const adjustAmount = finalLiftAmount * 0.06;
                    robotArm.upperArm.rotation.x += adjustAmount;
                    robotArm.forearm.rotation.x += adjustAmount * 0.5;
                    robotArm.wrist.rotation.x -= (adjustAmount + adjustAmount * 0.5);
                    robotArm.hand.rotation.x = -Math.PI / 2; // 确保套筒垂直向下
                    
                    // 强制更新一次位置
                    updateScrewPosition();
                    
                    // 强制更新机械臂矩阵
                    robotArm.group.updateMatrix();
                    robotArm.group.updateMatrixWorld(true);
                    robotArm.upperArm.updateMatrix();
                    robotArm.upperArm.updateMatrixWorld(true);
                    robotArm.forearm.updateMatrix();
                    robotArm.forearm.updateMatrixWorld(true);
                    robotArm.wrist.updateMatrix();
                    robotArm.wrist.updateMatrixWorld(true);
                    robotArm.hand.updateMatrix();
                    robotArm.hand.updateMatrixWorld(true);
                    
                    // 立即保存状态
                    const step3State = saveArmState();
                    localStorage.setItem('step3ArmState', JSON.stringify(step3State));
                    // 同时保存到sessionStorage作为备份
                    sessionStorage.setItem('step3ArmState_backup', JSON.stringify(step3State));
                    console.log('步骤3完成时立即保存状态:', step3State);
                    
                    // 移除其他可能的状态保存点
                    localStorage.removeItem('savedArmState');
                    localStorage.removeItem('step2ArmState');
                }
                break;
                
            case 4: // 放入盒子
                // 检查螺丝是否接近盒子
                const distanceToBox = screw.position.distanceTo(BOX_POSITION);
                stepCompleted = distanceToBox < BOX_THRESHOLD;
                break;
                
            case 5: // 实验完成
                // 实验已完成，自动设置为成功状态
                stepCompleted = true;
                break;
        }
    }
    
    // 检查当前步骤是否完成
    function checkCurrentStep() {
        // 检查步骤进度
        checkStepProgress();
        
        // 根据步骤完成情况显示反馈
        const feedbackMsgs = document.querySelectorAll('.feedback-message');
        feedbackMsgs.forEach(msg => {
            msg.style.display = 'block';
        });
        
        // 获取所有提交按钮
        const submitButtons = document.querySelectorAll('.submit-step-btn');
        
        if (stepCompleted) {
            feedbackMsgs.forEach(msg => {
                msg.className = 'feedback-message feedback-success';
                
                switch(currentStep) {
                    case 1:
                        msg.textContent = '很好！您已成功将机械臂前端套筒部分定位到螺丝钉上方。';
                        // 保存第一步完成时的机械臂状态
                        saveArmState();
                        // 在本地存储中保存，以便页面重新加载后仍能恢复
                        localStorage.setItem('savedArmState', JSON.stringify(savedArmState));
                        console.log('已保存机械臂状态:', savedArmState);
                        break;
                    case 2:
                        msg.textContent = '很好！套筒已正确扣住螺丝。';
                        // 保存第二步完成时的机械臂状态
                        saveArmState();
                        // 在本地存储中保存，以便步骤三可以使用
                        localStorage.setItem('step2ArmState', JSON.stringify(savedArmState));
                        console.log('已保存步骤二完成时的机械臂状态:', savedArmState);
                        break;
                    case 3:
                        msg.textContent = '很好！您已成功拧下螺丝。';
                        // 不再在这里保存状态，因为已经在checkStepProgress中保存了
                        break;
                    case 4:
                        msg.textContent = '很好！您已成功将机械臂移动到收纳盒上方。现在可以释放螺丝了。';
                        // 显示释放螺丝按钮
                        document.querySelectorAll('.release-screw-btn').forEach(btn => {
                            btn.style.display = 'block';
                        });
                        // 隐藏提交按钮，等待用户点击释放螺丝按钮
                        submitButtons.forEach(btn => {
                            btn.style.display = 'none';
                        });
                        return; // 不显示提交按钮，等待用户点击释放螺丝
                        break;
                }
            });
            
            // 显示所有提交按钮（除了步骤4特殊处理）
            if (currentStep !== 4) {
                submitButtons.forEach(btn => {
                    btn.style.display = 'block';
                });
            }
        } else {
            feedbackMsgs.forEach(msg => {
                msg.className = 'feedback-message feedback-error';
                
                switch(currentStep) {
                    case 1:
                        msg.textContent = '请将机械臂前端套筒部分定位到螺丝钉上方。';
                        break;
                    case 2:
                        msg.textContent = '套筒尚未正确扣住螺丝，请调整套筒朝向和位置。';
                        break;
                    case 3:
                        msg.textContent = '请沿逆时针方向旋转套筒，直到完全拧出螺丝。需要持续旋转，让螺丝逐渐上升直到完全脱离。';
                        break;
                    case 4:
                        msg.textContent = '请将拧下的螺丝移动到收纳盒位置。';
                        // 确保释放螺丝按钮隐藏
                        document.querySelectorAll('.release-screw-btn').forEach(btn => {
                            btn.style.display = 'none';
                        });
                        break;
                }
            });
            
            // 隐藏所有提交按钮
            submitButtons.forEach(btn => {
                btn.style.display = 'none';
            });
        }
    }
    
    // 显示操作提示
    function showOperationHint() {
        const hintElement = document.getElementById('operation-hint');
        let message = "";
        
        switch(currentStep) {
            case 1:
                message = "左键拖动机械臂底座可移动位置，按住Shift键拖动可旋转底座。右键拖动/滚轮可调整视角。";
                break;
            case 2:
                message = "拖动机械臂各关节，将套筒精确扣住螺丝头部。右键拖动/滚轮可调整视角。";
                break;
            case 3:
                message = "旋转套筒以拧出螺丝。右键拖动/滚轮可调整视角。";
                break;
            case 4:
                message = "拖动机械臂底座可移动位置，也可以拖动上臂、前臂、手腕和套筒等各个关节，灵活调整机械臂姿势，将螺丝放入收集盒。按住Shift键拖动底座可旋转底座方向。右键拖动/滚轮可调整视角。";
                break;
        }
        
        hintElement.textContent = message;
        hintElement.style.display = 'block';
    }
    
    // 显示操作反馈
    function showOperationFeedback(message) {
        const hintElement = document.getElementById('operation-hint');
        hintElement.textContent = message;
        hintElement.style.display = 'block';
    }
    
    // 页面加载完成后初始化
    document.addEventListener('DOMContentLoaded', function() {
        console.log("DOM已加载，开始初始化");
        
        try {
            init();
            console.log("初始化成功");
            
            // 如果是第三步，立即确保螺丝方向正确
            if (currentStep === 3 && screw) {
                // 确保螺丝保持垂直方向
                screw.rotation.set(0, 0, 0);
                console.log("初始化时已设置第三步螺丝方向为垂直");
            }
        } catch (error) {
            console.error("初始化过程中发生错误:", error);
        }
        
        // 特别处理第二步
        if (currentStep === 2) {
            // 显示临时提示，告知用户系统正在尝试恢复上一步位置
            const hintElement = document.getElementById('operation-hint');
            if (hintElement) {
                hintElement.textContent = "正在恢复第一步时的机械臂位置...";
                hintElement.style.display = 'block';
                
                // 设置一个短暂的延时，之后更新为正常操作提示
                setTimeout(function() {
                    showOperationHint();
                }, 2000);
            }
            
            console.log("当前是第二步，将尝试恢复第一步完成时的位置");
        }
        // 特别处理第三步
        else if (currentStep === 3) {
            // 显示临时提示，告知用户系统正在尝试恢复上一步位置
            const hintElement = document.getElementById('operation-hint');
            if (hintElement) {
                hintElement.textContent = "正在恢复第二步时的机械臂位置...";
                hintElement.style.display = 'block';
                
                // 设置一个短暂的延时，之后更新为正常操作提示
                setTimeout(function() {
                    showOperationHint();
                }, 2000);
            }
            
            console.log("当前是第三步，将尝试恢复第二步完成时的位置");
            
            // 确保额外一次设置螺丝方向
            if (screw) {
                setTimeout(function() {
                    screw.rotation.set(0, 0, 0);
                    console.log("延时再次确认第三步螺丝方向为垂直");
                }, 500); // 延迟500毫秒再次确认
            }
        }
        // 特别处理第四步
        else if (currentStep === 4) {
            // 显示临时提示，告知用户系统正在尝试恢复上一步位置
            const hintElement = document.getElementById('operation-hint');
            if (hintElement) {
                hintElement.textContent = "正在恢复第三步时的机械臂位置...";
                hintElement.style.display = 'block';
                
                // 设置一个短暂的延时，之后更新为正常操作提示
                setTimeout(function() {
                    showOperationHint();
                }, 2000);
            }
            
            console.log("当前是第四步，将尝试恢复第三步完成时的位置");
        }
        
        // 为检查步骤按钮添加事件监听器
        document.querySelectorAll('.check-step-btn').forEach(btn => {
            btn.addEventListener('click', function() {
                checkCurrentStep();
            });
        });
        
        // 为释放螺丝按钮添加事件监听器
        document.querySelectorAll('.release-screw-btn').forEach(btn => {
            btn.addEventListener('click', function() {
                releaseScrew();
            });
        });
        
        // 为自动拧出螺丝按钮添加事件监听器
        document.querySelectorAll('[id^="auto-unscrew-btn"]').forEach(btn => {
            btn.addEventListener('click', function() {
                autoUnscrewStep();
            });
        });
        
        // 为所有表单添加提交事件监听器
        document.querySelectorAll('form[id^="step-form"]').forEach(form => {
            form.addEventListener('submit', function(e) {
                // 如果是第三步，确保在提交前螺丝方向和位置正确
                if (currentStep === 3 && screw) {
                    // 固定螺丝方向为垂直向下
                    screw.rotation.set(0, 0, 0);
                    
                    // 确保步骤完成标记已设置
                    if (!stepCompleted && screw.userData.rotationAmount >= ROTATION_THRESHOLD) {
                        stepCompleted = true;
                    }
                    
                    // 重新保存状态以确保正确的螺丝方向和位置被保存
                    const step3State = saveArmState();
                    localStorage.setItem('step3ArmState', JSON.stringify(step3State));
                    sessionStorage.setItem('step3ArmState_backup', JSON.stringify(step3State));
                    
                    console.log('提交表单前重新保存了第三步状态，确保螺丝方向和位置正确');
                }
            });
        });
        
        // 添加页面卸载前的事件处理，再次确保正确保存状态
        window.addEventListener('beforeunload', function() {
            if (currentStep === 3 && screw && stepCompleted) {
                // 确保螺丝方向正确
                screw.rotation.set(0, 0, 0);
                
                // 保存状态
                const step3State = saveArmState();
                localStorage.setItem('step3ArmState', JSON.stringify(step3State));
                sessionStorage.setItem('step3ArmState_backup', JSON.stringify(step3State));
                
                console.log('页面卸载前已保存第三步状态，确保螺丝方向和位置正确');
            }
        });
    });
    
    // 鼠标离开画布处理
    function onMouseLeave(event) {
        console.log("鼠标离开画布");
        
        // 重置鼠标样式
        document.body.style.cursor = 'auto';
        
        // 如果有选中的对象，检查步骤进度
        if (SELECTED !== null) {
            checkStepProgress();
        }
        
        // 重置选中状态
        SELECTED = null;
        currentDraggingJoint = null;
    }
    
    // 保存机械臂状态
    function saveArmState() {
        console.log('正在保存机械臂状态，当前步骤:', currentStep);
        
        savedArmState = {
            basePosition: {
                x: robotArm.group.position.x,
                y: robotArm.group.position.y,
                z: robotArm.group.position.z
            },
            baseRotation: {
                x: robotArm.group.rotation.x,
                y: robotArm.group.rotation.y,
                z: robotArm.group.rotation.z
            },
            upperArmRotation: {
                x: robotArm.upperArm.rotation.x,
                y: robotArm.upperArm.rotation.y,
                z: robotArm.upperArm.rotation.z
            },
            elbowRotation: {
                x: robotArm.elbow.rotation.x,
                y: robotArm.elbow.rotation.y,
                z: robotArm.elbow.rotation.z
            },
            forearmRotation: {
                x: robotArm.forearm.rotation.x,
                y: robotArm.forearm.rotation.y,
                z: robotArm.forearm.rotation.z
            },
            wristRotation: {
                x: robotArm.wrist.rotation.x,
                y: robotArm.wrist.rotation.y,
                z: robotArm.wrist.rotation.z
            },
            handPosition: {
                x: robotArm.hand.position.x,
                y: robotArm.hand.position.y,
                z: robotArm.hand.position.z
            },
            handRotation: {
                x: robotArm.hand.rotation.x,
                y: robotArm.hand.rotation.y,
                z: robotArm.hand.rotation.z
            }
        };
        
        // 如果处于第三步，总是保存螺丝的状态（不管是否完成第三步）
        if (currentStep === 3 && screw) {
            console.log('保存步骤三螺丝状态, 螺丝位置:', screw.position, '旋转量:', screw.userData.rotationAmount || 0);
            
            // 计算螺丝的最终上升高度 - 统一使用相同的计算逻辑
            let liftAmount = 0;
            if (stepCompleted || (screw.userData.rotationAmount && screw.userData.rotationAmount >= ROTATION_THRESHOLD)) {
                // 如果步骤完成或旋转量已足够
                const finalRotation = Math.max(ROTATION_THRESHOLD, screw.userData.rotationAmount || 0);
                liftAmount = Math.min(3.5, finalRotation * 0.5);
                
                // 如果已有保存的最终上升高度，优先使用它
                if (screw.userData.finalLiftAmount !== undefined) {
                    liftAmount = screw.userData.finalLiftAmount;
                }
                
                // 不在这里修改螺丝位置，只记录位置信息
            } else {
                // 如果旋转未完成，使用当前旋转量计算
                liftAmount = Math.min(3.5, (screw.userData.rotationAmount || 0) * 0.5);
            }
            
            // 确保螺丝已经被标记为移除
            screw.userData.isRemoved = true;
            
            // 使用用户设置的位置和旋转（如果有的话）
            let screwPosition = {
                x: screw.position.x,
                y: screw.position.y,
                z: screw.position.z
            };
            
            let screwRotation = {
                x: screw.rotation.x,
                y: screw.rotation.y,
                z: screw.rotation.z
            };
            
            // 如果有用户设置的位置，优先使用
            if (screw.userData.userSetPosition) {
                screwPosition = {
                    x: screw.userData.userSetPosition.x,
                    y: screw.userData.userSetPosition.y,
                    z: screw.userData.userSetPosition.z
                };
            }
            
            // 如果有用户设置的旋转，优先使用
            if (screw.userData.userSetRotation) {
                screwRotation = screw.userData.userSetRotation;
            }
            
            savedArmState.screwState = {
                position: screwPosition,
                rotation: screwRotation,
                rotationAmount: stepCompleted ? Math.max(ROTATION_THRESHOLD, screw.userData.rotationAmount || 0) : (screw.userData.rotationAmount || 0),
                isRemoved: true,
                liftAmount: liftAmount
            };
            
            // 明确设置robotArm持有螺丝的状态
            robotArm.isHoldingScrew = true;
            
            console.log('已保存螺丝状态:', savedArmState.screwState);
            
            // 立即保存到sessionStorage作为备份，不需要检查是否完成
            try {
                sessionStorage.setItem('step3ArmState_backup', JSON.stringify(savedArmState));
                console.log('步骤3状态已备份到sessionStorage');
            } catch (e) {
                console.warn('无法保存到sessionStorage:', e);
            }
        }
        
        return savedArmState;
    }
    
    // 恢复机械臂状态
    function restoreArmState(state) {
        if(!state) return false;
        
        try {
            // 恢复位置和旋转
            robotArm.group.position.set(state.basePosition.x, state.basePosition.y, state.basePosition.z);
            robotArm.group.rotation.set(state.baseRotation.x, state.baseRotation.y, state.baseRotation.z);
            
            robotArm.upperArm.rotation.set(state.upperArmRotation.x, state.upperArmRotation.y, state.upperArmRotation.z);
            robotArm.elbow.rotation.set(state.elbowRotation.x, state.elbowRotation.y, state.elbowRotation.z);
            robotArm.forearm.rotation.set(state.forearmRotation.x, state.forearmRotation.y, state.forearmRotation.z);
            robotArm.wrist.rotation.set(state.wristRotation.x, state.wristRotation.y, state.wristRotation.z);
            
            robotArm.hand.position.set(state.handPosition.x, state.handPosition.y, state.handPosition.z);
            robotArm.hand.rotation.set(state.handRotation.x, state.handRotation.y, state.handRotation.z);
            
            // 如果有螺丝状态，同时恢复螺丝
            if (state.screwState && screw) {
                // 恢复螺丝位置
                screw.position.set(
                    state.screwState.position.x,
                    state.screwState.position.y,
                    state.screwState.position.z
                );
                
                // 恢复螺丝旋转
                screw.rotation.set(
                    state.screwState.rotation.x,
                    state.screwState.rotation.y,
                    state.screwState.rotation.z
                );
                
                // 恢复螺丝旋转量
                screw.userData.rotationAmount = state.screwState.rotationAmount;
                
                // 恢复螺丝是否被拧出的状态
                screw.userData.isRemoved = state.screwState.isRemoved;
                
                // 恢复提升高度
                if (state.screwState.liftAmount !== undefined) {
                    screw.userData.finalLiftAmount = state.screwState.liftAmount;
                }
                
                // 保存用户设置的位置和旋转，以防止其他函数重置
                screw.userData.userSetPosition = screw.position.clone();
                screw.userData.userSetRotation = {
                    x: screw.rotation.x,
                    y: screw.rotation.y,
                    z: screw.rotation.z
                };
                
                // 检查是否需要设置机械臂持有螺丝
                if (currentStep >= 3) {
                    robotArm.isHoldingScrew = true;
                    console.log('恢复状态：机械臂现在持有螺丝');
                }
            }
            
            console.log('已恢复机械臂状态');
            return true;
        } catch(e) {
            console.error('恢复机械臂状态失败:', e);
            return false;
        }
    }
    
    // 添加释放螺丝钉的函数
    function releaseScrew() {
        if (currentStep === 4 && stepCompleted && robotArm.isHoldingScrew && screw) {
            console.log('正在执行释放螺丝操作');
            
            // 螺丝掉落动画
            const startPosition = screw.position.clone();
            
            // 获取黑色盒子内部的顶部表面位置
            const targetPosition = BOX_POSITION.clone();
            
            // 盒子基础高度是2（位置在y=2），盒子底部高度1.5，盒子内部高度2
            // 所以内部盒子的顶部表面应该是 y = 2 + 2 = 4
            targetPosition.y = BOX_POSITION.y + 2; // 准确定位到黑色盒子内部的顶部表面
            
            // 记录数据以便观察
            console.log('螺丝释放：', {
                盒子位置: BOX_POSITION.clone(),
                起始位置: startPosition.clone(),
                目标位置: targetPosition.clone()
            });
            
            const startTime = Date.now();
            const duration = 1000; // 掉落动画持续1秒
            
            // 螺丝掉落动画函数
            function animateDropScrew() {
                const currentTime = Date.now();
                const elapsed = currentTime - startTime;
                
                if (elapsed < duration) {
                    const progress = elapsed / duration;
                    
                    // 计算当前位置（添加抛物线效果）
                    const currentPosition = new THREE.Vector3(
                        startPosition.x + (targetPosition.x - startPosition.x) * progress,
                        startPosition.y + (targetPosition.y - startPosition.y) * progress - 2 * Math.sin(progress * Math.PI), // 抛物线效果
                        startPosition.z + (targetPosition.z - startPosition.z) * progress
                    );
                    
                    // 更新螺丝位置
                    screw.position.copy(currentPosition);
                    
                    // 添加一些旋转效果，让螺丝在飞行过程中旋转
                    screw.rotation.x += 0.1;
                    screw.rotation.z += 0.1;
                    
                    // 继续动画
                    requestAnimationFrame(animateDropScrew);
                } else {
                    // 动画完成，螺丝放在盒子上
                    screw.position.copy(targetPosition);
                    
                    // 设置螺丝平躺在盒子上
                    // Math.PI/2让螺丝平躺（垂直于y轴）
                    screw.rotation.x = Math.PI/2; 
                    screw.rotation.y = 0;
                    screw.rotation.z = 0;
                    
                    // 记录最终位置以便观察
                    console.log('螺丝最终位置:', screw.position.clone());
                    
                    robotArm.isHoldingScrew = false;
                    
                    // 显示成功消息
                    const feedbackMsgs = document.querySelectorAll('.feedback-message');
                    feedbackMsgs.forEach(msg => {
                        msg.className = 'feedback-message feedback-success';
                        msg.textContent = '很好！您已成功将螺丝放在黑色收纳盒上表面。';
                    });
                    
                    // 显示提交按钮
                    document.querySelectorAll('.submit-step-btn').forEach(btn => {
                        btn.style.display = 'block';
                    });
                    
                    // 隐藏释放螺丝按钮
                    document.querySelectorAll('.release-screw-btn').forEach(btn => {
                        btn.style.display = 'none';
                    });
                }
                
                // 强制渲染更新场景
                render();
            }
            
            // 开始动画
            animateDropScrew();
        }
    }
    
    // 添加一个默认位置函数，避免代码重复
    function useDefaultStep4Position() {
        console.log('使用默认的第四步起始位置');
        
        // 强制清除旧状态
        document.getElementById('feedback-message').style.display = 'none';
        
        // 螺丝已拧出的高度
        const liftAmount = Math.min(3.5, robotArm.screwRotation * 0.5);
        
        // 设置机械臂在一个合理的起始位置
        // 位于螺丝原始位置左侧，已经抓住螺丝
        robotArm.group.position.set(
            -8, // 放在工作区左侧
            0,  // y位置保持为0，确保底座不上升
            0   // 中间区域
        );
        
        // 设置机械臂旋转，使其面向盒子方向
        robotArm.group.rotation.y = Math.PI / 4; // 45度，朝向盒子
        
        // 设置各关节角度为自然姿势，采用原始的默认设置
        robotArm.upperArm.rotation.x = -Math.PI / 4; // -45度
        robotArm.forearm.rotation.x = -Math.PI / 6;  // -30度
        robotArm.wrist.rotation.x = 0;
        robotArm.hand.rotation.x = -Math.PI / 2;     // -90度，套筒朝下
        robotArm.hand.position.z = 2;                // 套筒向前伸出
        
        // 根据螺丝的高度微调机械臂关节角度 
        // 此时只需要小幅度调整，因为起始姿势已经合理
        const adjustAmount = liftAmount * 0.05; // 使用较小的调整系数
        
        // 轻微调整关节角度，使套筒位置与螺丝高度匹配
        robotArm.upperArm.rotation.x += adjustAmount;
        robotArm.forearm.rotation.x += adjustAmount * 0.5;
        
        // 调整手腕角度，补偿上臂和前臂的旋转，确保套筒保持垂直向下
        robotArm.wrist.rotation.x -= (adjustAmount + adjustAmount * 0.5);
        
        // 确保手部套筒始终垂直向下
        robotArm.hand.rotation.x = -Math.PI / 2;
        
        // 强制更新机械臂的矩阵，确保所有部件正确连接
        robotArm.group.updateMatrix();
        robotArm.group.updateMatrixWorld(true);
        robotArm.upperArm.updateMatrix();
        robotArm.upperArm.updateMatrixWorld(true);
        robotArm.elbow.updateMatrix();
        robotArm.elbow.updateMatrixWorld(true);
        robotArm.forearm.updateMatrix();
        robotArm.forearm.updateMatrixWorld(true);
        robotArm.wrist.updateMatrix();
        robotArm.wrist.updateMatrixWorld(true);
        robotArm.hand.updateMatrix();
        robotArm.hand.updateMatrixWorld(true);
        
        // 设置螺丝已经被拔出并附着在套筒上
        if (screw) {
            // 确保螺丝属性正确设置
            screw.userData.isRemoved = true;
            screw.userData.rotationAmount = ROTATION_THRESHOLD; // 设置为阈值以表示已完成第三步
            
            // 确保机械臂标记为持有螺丝
            robotArm.isHoldingScrew = true;
            
            // 更新螺丝位置，使其附着在套筒前端
            updateScrewPosition();
            
            console.log('已设置螺丝附着在套筒上，位置:', screw.position);
        }
        
        // 强制更新一次，确保位置正确
        updateRobotArmPose();
        
        // 显示操作提示
        showOperationHint();
    }
    
    // 添加一个附着螺丝到套筒的辅助函数
    function attachScrewToHand() {
        if (!screw) return;
        
        console.log('将螺丝附着到套筒上');
        
        // 计算螺丝位置，与第三步中相同的逻辑
        const liftAmount = Math.min(3.5, ROTATION_THRESHOLD * 0.5);
        
        // 将螺丝附着到套筒
        screw.position.y = SCREW_POSITION.y + liftAmount; // 与步骤3的计算保持一致
        screw.position.x = robotArm.group.position.x;
        screw.position.z = robotArm.group.position.z + 3.5; // 套筒前端
        
        // 标记螺丝已被移除
        screw.userData.isRemoved = true;
        screw.userData.rotationAmount = ROTATION_THRESHOLD; // 确保满足步骤三完成条件
        robotArm.isHoldingScrew = true;
        
        console.log('螺丝已附着到套筒，位置:', screw.position);
    }
    
    // 在moveJoint函数末尾，添加更新矩阵的代码
    function moveJoint(joint, angle) {
        if(joint == null) return;
        
        // ... existing code ...
        
        // 更新关节角度后，强制更新所有矩阵确保连接正确
        robotArm.group.updateMatrix();
        robotArm.group.updateMatrixWorld(true);
        robotArm.upperArm.updateMatrix();
        robotArm.upperArm.updateMatrixWorld(true);
        robotArm.elbow.updateMatrix();
        robotArm.elbow.updateMatrixWorld(true);
        robotArm.forearm.updateMatrix();
        robotArm.forearm.updateMatrixWorld(true);
        robotArm.wrist.updateMatrix();
        robotArm.wrist.updateMatrixWorld(true);
        robotArm.hand.updateMatrix();
        robotArm.hand.updateMatrixWorld(true);
        
        // 如果机械臂手上有螺丝，更新螺丝位置
        if (screw && screw.isGrabbed) {
            updateScrewPosition();
        }
    }
    
    // 自动拧出螺丝的函数
    function autoUnscrewStep() {
        if (currentStep !== 3) return;
        
        console.log("开始自动拧出螺丝");
        
        // 获取参数输入值
        const screwSize = document.getElementById('screw-size').value;
        const motorSpeed = parseInt(document.getElementById('motor-speed').value);
        const threadCount = parseInt(document.getElementById('thread-count').value);
        
        // 获取用户输入的提取速度
        const userExtractionSpeedInput = document.getElementById('user-extraction-speed');
        const userExtractionSpeed = parseFloat(userExtractionSpeedInput.value);
        
        if (isNaN(userExtractionSpeed) || userExtractionSpeed <= 0) {
            // 提示用户需要输入有效的提取速度
            const feedbackMsgs = document.querySelectorAll('.feedback-message');
            feedbackMsgs.forEach(msg => {
                msg.className = 'feedback-message feedback-warning';
                msg.textContent = '请输入您估计的提取速度值';
                msg.style.display = 'block';
            });
            return;
        }
        
        // 根据螺栓规格确定螺距
        let threadPitch = 0.7; // 默认值：M4的螺距
        if (screwSize === 'M3') {
            threadPitch = 0.5;
        } else if (screwSize === 'M4') {
            threadPitch = 0.7;
        } else if (screwSize === 'M5') {
            threadPitch = 0.8;
        } else if (screwSize === 'M6') {
            threadPitch = 1.0;
        } else if (screwSize === 'M8') {
            threadPitch = 1.25;
        } else if (screwSize === 'M10') {
            threadPitch = 1.5;
        } else if (screwSize === 'M12') {
            threadPitch = 1.75;
        } else if (screwSize === 'M14') {
            threadPitch = 2.0;
        }
        
        // 计算紧固件沿轴向的提取速度 (mm/min)
        const extractionSpeed = threadPitch * motorSpeed * threadCount;
        
        // 更新提取速度（仅在后台存储，不显示）
        document.getElementById('extraction-speed').textContent = extractionSpeed.toFixed(2) + " mm/min";
        
        // 计算用户输入速度与实际速度的差异比例
        const speedDifference = Math.abs(userExtractionSpeed - extractionSpeed) / extractionSpeed;
        
        // 保存速度差异信息用于结束时判断
        const speedTooFast = userExtractionSpeed > extractionSpeed && speedDifference > EXTRACTION_SPEED_THRESHOLD;
        const speedTooSlow = userExtractionSpeed < extractionSpeed && speedDifference > EXTRACTION_SPEED_THRESHOLD;
        const speedInRange = speedDifference <= EXTRACTION_SPEED_THRESHOLD;
        
        // 显示操作反馈
        const feedbackMsgs = document.querySelectorAll('.feedback-message');
        feedbackMsgs.forEach(msg => {
            msg.className = 'feedback-message feedback-info';
            msg.textContent = '正在自动拧出螺丝，请等待...';
            msg.style.display = 'block';
        });
        
        // 禁用所有自动拧出按钮
        document.querySelectorAll('[id^="auto-unscrew-btn"]').forEach(btn => {
            btn.disabled = true;
        });
        
        // 设置初始旋转量（如果尚未设置）
        if (!screw.userData.rotationAmount) {
            screw.userData.rotationAmount = 0;
        }
        
        // 记录初始位置，确保一致性
        const initialPosition = {
            x: screw.position.x,
            y: SCREW_POSITION.y, // 使用基准位置
            z: screw.position.z
        };
        
        // 确保螺丝保持正确的初始方向
        screw.rotation.set(0, 0, 0);
        
        // 创建一个动画循环，逐渐旋转螺丝
        let animationId;
        
        // 根据提取速度调整旋转速度
        // 将mm/min转换为每帧的旋转量
        // 假设60fps，将分钟转换为每帧的毫米移动
        // 使用用户输入的速度值代替计算值
        const mmPerFrame = userExtractionSpeed / (60 * 60); // 每分钟 -> 每帧
        
        // 旋转量与上升高度关系：liftAmount = rotationAmount * 0.5
        // 因此旋转量 = 上升高度 / 0.5 = 上升高度 * 2
        // 添加速度减缓系数0.3，使旋转速度放缓
        const speedReductionFactor = 0.3; // 速度减缓系数，小于1表示减慢速度
        const rotateSpeed = mmPerFrame * 2 * speedReductionFactor;
        
        console.log("用户输入的提取速度:", userExtractionSpeed, "计算的旋转速度:", rotateSpeed);
        
        const totalRotationNeeded = ROTATION_THRESHOLD + 0.5; // 确保超过阈值
        
        // 估算动画完成所需时间（毫秒）
        const estimatedDuration = (totalRotationNeeded / rotateSpeed) * (1000 / 60); // 假设60fps
        console.log("估计动画完成时间（毫秒）:", estimatedDuration);
        
        // 启动力数据可视化轮播
        startForceVisualizationSlideshow(estimatedDuration);
        
        function rotateStep() {
            // 检查是否已达到所需旋转量
            if (screw.userData.rotationAmount >= totalRotationNeeded) {
                // 完成旋转
                console.log("自动拧出螺丝完成，旋转量:", screw.userData.rotationAmount);
                
                // 取消动画
                cancelAnimationFrame(animationId);
                
                // 停止力数据可视化轮播（如果没有自然结束）
                if (forceVisualizationInterval) {
                    clearInterval(forceVisualizationInterval);
                    forceVisualizationInterval = null;
                    
                    // 确保显示当前规格和转速的图片
                    updateForceVisualizationImage();
                }
                
                // 再次确保螺丝保持正确方向
                screw.rotation.set(0, 0, 0);
                
                // 计算最终螺丝上升高度 - 使用统一的计算方法
                const finalLiftAmount = Math.min(3.5, totalRotationNeeded * 0.5);
                
                // 确保最终位置一致性 - 只修改Y坐标（高度）
                screw.position.set(
                    initialPosition.x,
                    SCREW_POSITION.y + finalLiftAmount,
                    initialPosition.z
                );
                
                if (speedInRange) {
                    // 速度在合理范围内，正常完成
                    feedbackMsgs.forEach(msg => {
                        msg.className = 'feedback-message feedback-success';
                        msg.textContent = '很好！您已成功拧下螺丝。';
                    });
                    
                    // 设置步骤完成标记
                    stepCompleted = true;
                    screw.userData.step3Saved = true;
                    screw.userData.rotationAmount = totalRotationNeeded;
                    screw.userData.finalLiftAmount = finalLiftAmount;
                    
                    // 保存状态前确保螺丝方向和位置正确
                    const step3State = saveArmState();
                    localStorage.setItem('step3ArmState', JSON.stringify(step3State));
                    sessionStorage.setItem('step3ArmState_backup', JSON.stringify(step3State));
                    
                    // 显示提交按钮
                    document.querySelectorAll('.submit-step-btn').forEach(btn => {
                        btn.style.display = 'block';
                    });
                } else {
                    // 速度不在合理范围内，显示碎屑效果
                    if (speedTooFast) {
                        // 如果速度过快，显示黑色碎屑并给出提示
                        console.log("显示速度过快碎屑效果");
                        createDebrisParticles(screw.position, 0x000000, 'fast');
                        
                        feedbackMsgs.forEach(msg => {
                            msg.className = 'feedback-message feedback-error';
                            msg.textContent = '速度过快！拧出力度过大导致螺丝损坏。';
                        });
                    } else {
                        // 如果速度过慢，显示黑色碎屑并给出提示
                        console.log("显示速度过慢碎屑效果");
                        createDebrisParticles(screw.position, 0x000000, 'slow');
                        
                        feedbackMsgs.forEach(msg => {
                            msg.className = 'feedback-message feedback-warning';
                            msg.textContent = '速度过慢！拧出力度不足导致螺丝滑丝。';
                        });
                    }
                    
                    // 创建重新开始按钮
                    const resetButtons = document.querySelectorAll('.reset-step-btn');
                    if (resetButtons.length === 0) {
                        // 如果按钮不存在，创建按钮
                        const resetButton = document.createElement('button');
                        resetButton.className = 'reset-step-btn btn btn-danger w-100 mt-2';
                        resetButton.textContent = '重新开始';
                        resetButton.addEventListener('click', function() {
                            console.log("点击重新开始按钮，刷新页面");
                            window.location.reload();
                        });
                        
                        // 添加到每个控制面板
                        document.querySelectorAll('.control-panel').forEach(panel => {
                            const buttonContainer = document.createElement('div');
                            buttonContainer.className = 'd-grid gap-2 mt-3';
                            const clonedButton = resetButton.cloneNode(true);
                            // 确保克隆的按钮也有事件监听器
                            clonedButton.addEventListener('click', function() {
                                console.log("点击重新开始按钮，刷新页面");
                                window.location.reload();
                            });
                            buttonContainer.appendChild(clonedButton);
                            panel.appendChild(buttonContainer);
                        });
                    }
                    
                    // 不设置步骤完成标记
                    stepCompleted = false;
                }
                
                // 重新启用所有自动拧出按钮
                document.querySelectorAll('[id^="auto-unscrew-btn"]').forEach(btn => {
                    btn.disabled = false;
                });
                
                return;
            }
            
            // 执行旋转（只旋转机械臂手部，螺丝保持固定方向）
            robotArm.hand.rotation.z += rotateSpeed;
            
            // 增加旋转量计数（但不实际旋转螺丝）
            screw.userData.rotationAmount += rotateSpeed;
            
            // 螺丝上升（保持钉头朝上，身体朝下的固定方向，只做平移上升）
            let liftAmount = Math.min(3.5, screw.userData.rotationAmount * 0.5);
            screw.position.y = SCREW_POSITION.y + liftAmount;
            
            // 计算前一帧和当前帧的提升差值
            const prevLiftAmount = Math.min(3.5, (screw.userData.rotationAmount - rotateSpeed) * 0.5);
            const liftDelta = liftAmount - prevLiftAmount;
            
            // 调整上臂角度，使套筒随螺丝钉上升 - 只应用增量变化
            const adjustAmount = liftDelta * 0.06; // 角度调整系数，减小系数
            robotArm.upperArm.rotation.x += adjustAmount; // 增量调整
            
            // 同时微调前臂角度，保持套筒水平位置
            robotArm.forearm.rotation.x += adjustAmount * 0.5; // 也改为同方向
            
            // 调整手腕角度，确保套筒始终朝向垂直向下
            // 计算需要补偿的角度，以保持垂直向下
            robotArm.wrist.rotation.x -= (adjustAmount + adjustAmount * 0.5);
            
            // 确保手部套筒始终保持垂直向下
            robotArm.hand.rotation.x = -Math.PI / 2;
            
            // 确保每一帧螺丝都保持正确方向
            screw.rotation.set(0, 0, 0);
            
            // 渲染
            render();
            
            // 继续下一帧
            animationId = requestAnimationFrame(rotateStep);
        }
        
        // 开始旋转动画
        animationId = requestAnimationFrame(rotateStep);
    }
    
    // 添加参数监听，实时更新提取速度显示
    document.addEventListener('DOMContentLoaded', function() {
        // 仅当在步骤3时添加事件监听器
        if (currentStep === 3) {
            const screwSizeSelect = document.getElementById('screw-size');
            const motorSpeedInput = document.getElementById('motor-speed');
            const threadCountSelect = document.getElementById('thread-count');
            const userSpeedInput = document.getElementById('user-extraction-speed');
            const speedFeedback = document.getElementById('extraction-speed-feedback');
            
            // 添加自动拧出螺丝按钮的点击事件监听器
            document.querySelectorAll('[id^="auto-unscrew-btn"]').forEach(btn => {
                btn.addEventListener('click', autoUnscrewStep);
                console.log('已添加自动拧出螺丝按钮事件监听器:', btn.id);
            });
            
            // 初始化力数据可视化图片
            updateForceVisualizationImage();
            
            // 添加参数变化监听器，实时更新力数据可视化图片
            screwSizeSelect.addEventListener('change', updateForceVisualizationImage);
            motorSpeedInput.addEventListener('change', updateForceVisualizationImage);
            
            function updateExtractionSpeed() {
                const screwSize = screwSizeSelect.value;
                const motorSpeed = parseInt(motorSpeedInput.value);
                const threadCount = parseInt(threadCountSelect.value);
                
                // 根据螺栓规格确定螺距
                let threadPitch = 0.7; // 默认值：M4的螺距
                if (screwSize === 'M3') {
                    threadPitch = 0.5;
                } else if (screwSize === 'M4') {
                    threadPitch = 0.7;
                } else if (screwSize === 'M5') {
                    threadPitch = 0.8;
                } else if (screwSize === 'M6') {
                    threadPitch = 1.0;
                } else if (screwSize === 'M8') {
                    threadPitch = 1.25;
                } else if (screwSize === 'M10') {
                    threadPitch = 1.5;
                } else if (screwSize === 'M12') {
                    threadPitch = 1.75;
                } else if (screwSize === 'M14') {
                    threadPitch = 2.0;
                }
                
                // 计算紧固件沿轴向的提取速度 (mm/min)
                const extractionSpeed = threadPitch * motorSpeed * threadCount;
                
                // 更新提取速度（仅在后台存储，不显示）
                document.getElementById('extraction-speed').textContent = extractionSpeed.toFixed(2) + " mm/min";
                
                // 参数变化时同时更新力数据可视化图片
                updateForceVisualizationImage();
            }
            
            // 初始计算
            updateExtractionSpeed();
            
            // 添加事件监听器
            screwSizeSelect.addEventListener('change', updateExtractionSpeed);
            motorSpeedInput.addEventListener('input', updateExtractionSpeed);
            threadCountSelect.addEventListener('change', updateExtractionSpeed);
            userSpeedInput.addEventListener('input', function() {
                // 获取当前的提取速度计算值
                const extractionSpeedText = document.getElementById('extraction-speed').textContent;
                const extractionSpeed = parseFloat(extractionSpeedText);
                
                // 检查用户输入与计算值的差异
                const userSpeed = parseFloat(userSpeedInput.value);
                
                if (!isNaN(userSpeed) && userSpeed > 0) {
                    const speedDifference = Math.abs(userSpeed - extractionSpeed) / extractionSpeed;
                    
                    if (speedDifference === 0) {
                        // 差异在可接受范围内
                        speedFeedback.className = 'text-success small';
                        speedFeedback.textContent = '预估速度合理';
                    } else if (speedDifference < EXTRACTION_SPEED_THRESHOLD) {
                        // 差异在可接受范围内
                        speedFeedback.className = 'text-success small';
                        speedFeedback.textContent = '预估速度可能不合理，如果机械臂仍以此速度提取待拆卸的螺丝，可能会产生碰撞磨损或有碎屑掉落';
                    }else if (userSpeed > extractionSpeed) {
                        // 用户输入速度过高
                        speedFeedback.className = 'text-danger small';
                        speedFeedback.textContent = '预估速度可能过高';
                    } else {
                        // 用户输入速度过低
                        speedFeedback.className = 'text-warning small';
                        speedFeedback.textContent = '预估速度可能过低';
                    }
                } else {
                    // 用户尚未输入有效值
                    speedFeedback.className = 'text-muted small';
                    speedFeedback.textContent = '请输入您估计的提取速度值';
                }
            });
        }
    });
    
    // 更新力数据可视化图片的函数
    function updateForceVisualizationImage() {
        if (currentStep !== 3) return;
        
        const screwSize = document.getElementById('screw-size').value;
        const motorSpeed = parseInt(document.getElementById('motor-speed').value);
        
        // 使用新的图片路径格式
        const imagePath = `/static/img/unscrew/${screwSize}_${motorSpeed}.png`;
        
        // 更新图片
        const imageElement = document.getElementById('force-visualization-image');
        if (imageElement) {
            imageElement.src = imagePath;
            console.log("更新力数据可视化图片:", imagePath);
        }
    }
    
    // 开始力数据可视化图片轮播 - 现在只显示一张静态图片，不再轮播
    function startForceVisualizationSlideshow(duration) {
        // 不再需要轮播，直接更新图片即可
        updateForceVisualizationImage();
    }
    
    // 创建碎屑粒子系统
    function createDebrisParticles(position, color, speedType) {
        console.log("创建碎屑粒子系统", position, color, speedType);
        
        // 如果已存在粒子系统，先移除
        if (debrisSystem) {
            scene.remove(debrisSystem);
            debrisSystem = null;
        }
        
        // 创建粒子几何体 - 增加粒子数量
        const particlesCount = 100; // 原来是50，增加到100
        const geometry = new THREE.BufferGeometry();
        const positions = new Float32Array(particlesCount * 3);
        const colors = new Float32Array(particlesCount * 3);
        const sizes = new Float32Array(particlesCount);
        
        // 颜色基础值（根据速度快慢设置不同颜色）
        let baseColor;
        if (speedType === 'fast') {
            baseColor = new THREE.Color(0x000000); // 橙红色表示速度过快
        } else {
            baseColor = new THREE.Color(0x000000); // 蓝色表示速度过慢
        }
        
        // 设置初始位置、颜色和大小
        for (let i = 0; i < particlesCount; i++) {
            // 坐标 - 以螺丝位置为中心，稍微散开更多
            positions[i * 3] = position.x + (Math.random() - 0.5) * 1.5; // 增加散布范围
            positions[i * 3 + 1] = position.y + Math.random() * 0.5; // 增加初始高度随机性
            positions[i * 3 + 2] = position.z + (Math.random() - 0.5) * 1.5; // 增加散布范围
            
            // 颜色 - 稍微随机化基础颜色
            colors[i * 3] = baseColor.r * (0.8 + Math.random() * 0.4);
            colors[i * 3 + 1] = baseColor.g * (0.8 + Math.random() * 0.4);
            colors[i * 3 + 2] = baseColor.b * (0.8 + Math.random() * 0.4);
            
            // 大小 - 增加粒子大小
            sizes[i] = Math.random() * 0.4 + 0.2; // 原来是0.2+0.1，增加到0.4+0.2
        }
        
        // 设置属性
        geometry.setAttribute('position', new THREE.BufferAttribute(positions, 3));
        geometry.setAttribute('color', new THREE.BufferAttribute(colors, 3));
        geometry.setAttribute('size', new THREE.BufferAttribute(sizes, 1));
        
        // 创建材质 - 增加基础大小
        const material = new THREE.PointsMaterial({
            size: 0.3, // 原来是0.1，增加到0.3
            vertexColors: true,
            transparent: true,
            opacity: 0.9, // 提高不透明度
            sizeAttenuation: true
        });
        
        // 创建粒子系统
        debrisSystem = new THREE.Points(geometry, material);
        scene.add(debrisSystem);
        
        // 保存粒子数据用于动画
        debrisParticles = {
            system: debrisSystem,
            velocity: [],
            gravity: 0.02,
            timeToLive: 150, // 增加生命周期，原来是100
            currentTime: 0
        };
        
        // 为每个粒子设置随机初始速度 - 增加初始速度
        for (let i = 0; i < particlesCount; i++) {
            debrisParticles.velocity.push({
                x: (Math.random() - 0.5) * 0.2, // 原来是0.1，增加到0.2
                y: Math.random() * 0.2 + 0.1,   // 原来是0.1+0.05，增加到0.2+0.1
                z: (Math.random() - 0.5) * 0.2  // 原来是0.1，增加到0.2
            });
        }
        
        // 开始动画
        animateDebris();
    }
    
    // 碎屑粒子动画
    function animateDebris() {
        if (!debrisParticles || debrisParticles.currentTime >= debrisParticles.timeToLive) {
            // 动画结束，移除粒子系统
            if (debrisSystem) {
                scene.remove(debrisSystem);
                debrisSystem = null;
            }
            debrisParticles = null;
            return;
        }
        
        // 更新粒子位置
        const positions = debrisParticles.system.geometry.attributes.position.array;
        
        for (let i = 0; i < positions.length / 3; i++) {
            // 应用速度
            positions[i * 3] += debrisParticles.velocity[i].x;
            positions[i * 3 + 1] += debrisParticles.velocity[i].y;
            positions[i * 3 + 2] += debrisParticles.velocity[i].z;
            
            // 应用重力（减小Y方向的速度）
            debrisParticles.velocity[i].y -= debrisParticles.gravity;
            
            // 检查是否触地
            if (positions[i * 3 + 1] < 0) {
                positions[i * 3 + 1] = 0; // 设置为地面高度
                debrisParticles.velocity[i].y = -debrisParticles.velocity[i].y * 0.3; // 反弹，但损失能量
                
                // 摩擦力减小水平速度
                debrisParticles.velocity[i].x *= 0.9;
                debrisParticles.velocity[i].z *= 0.9;
            }
        }
        
        // 标记位置需要更新
        debrisParticles.system.geometry.attributes.position.needsUpdate = true;
        
        // 更新不透明度
        const opacityFactor = 1 - (debrisParticles.currentTime / debrisParticles.timeToLive);
        debrisParticles.system.material.opacity = opacityFactor * 0.8;
        
        // 增加当前时间
        debrisParticles.currentTime++;
        
        // 渲染场景
        render();
        
        // 继续下一帧
        requestAnimationFrame(animateDebris);
    }
</script>
{% endblock %}